Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Regression: custom ostream formatting doesn't work with namespaced types after v7 #2130

Closed
alabuzhev opened this issue Feb 9, 2021 · 6 comments

Comments

@alabuzhev
Copy link
Contributor

Version: latest

operator<< in global namespace should be discoverable as long as it is defined before fmt facilities.
And it worked like that at least until v7 (godbolt).

However, at some point after v7, presumably after 16cac46, it stopped working (godbolt).

The latest trunk works if the offending code is commented (godbolt).

@LukeMauldin
Copy link

I have experienced this issue as well.

@vitaut
Copy link
Contributor

vitaut commented Mar 12, 2021

16cac46 is a fix for #1766. Unfortunately I don't know how to make both cases work. Considering that defining operator<< in a different namespace from the type is not well-supported anyway (depends on the order of inclusion), I recommend moving it to the appropriate namespace where it can be found by ADL (https://godbolt.org/z/q3MPM6):

namespace ns
{
    class test {};

    std::ostream& operator<<(std::ostream& Stream, test const&)
    {
        Stream << "ns::test\n";
        return Stream;
    }
}

If someone knows a solution that doesn't break #1766, a PR would be welcome.

@vitaut vitaut closed this as completed Mar 12, 2021
@vitaut
Copy link
Contributor

vitaut commented Mar 12, 2021

Clarified the limitation in the docs: d281018.

@alabuzhev
Copy link
Contributor Author

I recommend moving it to the appropriate namespace where it can be found by ADL

Unfortunately that's UB for std types :(

@vitaut
Copy link
Contributor

vitaut commented Mar 13, 2021

You can also provide a formatter specialization that delegates to operator<<:

template <>
struct fmt::formatter<ns::test> : formatter<std::string> {
  auto format(const ns::test& t, format_context& ctx) {
    std::ostringstream os;
    os << t;
    return formatter<std::string>::format(os.str(), ctx);
  }
};

We could make it simpler, something like:

template <> struct fmt::formatter<ns::test> : fmt::ostream_formatter<ns::test> {};

and this won't have the include order problem.

@alabuzhev
Copy link
Contributor Author

Thank you - a formatter specialization works as expected.
I've seen this API before, but it seemed quite cumbersome and I avoided it as long as << worked.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants