jhasse
jhasse

Reputation: 2603

Printing a type in a namespace via {fmt} and ostream

This answer mentions how you can include <fmt/ostream.h> to have ostream-printable types recognized by {fmt}. I noticed that it doesn't work when the type is in a namespace:

#include <fmt/format.h>
#include <fmt/ostream.h>

namespace foo {
  struct A {};
}

std::ostream& operator<<(std::ostream& os, const foo::A& a)
{
  return os << "A!";
}

int main()
{
  fmt::print("{}\n", foo::A{});
}

This will result in the old error (before including #include <fmt/ostream.h>) for a type without a namespace again:

fmt/core.h:1422:3: error: static_assert failed due to requirement 'fmt::formattable<foo::A>()' "Cannot format an argument. To make type T formattable provide a formatter<T> specialization: https://fmt.dev/latest/api.html#udt"
  static_assert(
  ^
fmt/core.h:1438:10: note: in instantiation of function template specialization 'fmt::detail::check<foo::A>' requested here
  return check<T>(arg_mapper<Context>().map(val));
         ^
fmt/core.h:1587:23: note: in instantiation of function template specialization 'fmt::detail::make_arg<true, fmt::basic_format_context<fmt::detail::buffer_appender<char>, char>, fmt::detail::type::custom_type, foo::A, 0>' requested here
        data_{detail::make_arg<
                      ^
fmt/core.h:1626:10: note: in instantiation of member function 'fmt::format_arg_store<fmt::basic_format_context<fmt::detail::buffer_appender<char>, char>, foo::A>::format_arg_store' requested here
  return {args...};
         ^
fmt/core.h:2114:28: note: in instantiation of function template specialization 'fmt::make_args_checked<foo::A, char [4], char>' requested here
  const auto& vargs = fmt::make_args_checked<Args...>(format_str, args...);
                           ^
main.cpp:15:8: note: in instantiation of function template specialization 'fmt::print<char [4], foo::A, char>' requested here
  fmt::print("{}\n", foo::A{});
       ^

Is there a way to make it work without implementing formatter<foo::A>?

Upvotes: 1

Views: 1062

Answers (2)

vrqq
vrqq

Reputation: 576

In fmt v8 the code valid, but invalid in fmt v9.
The C++ 20 standard do not support to overload to std::ostream<<

API v8 https://fmt.dev/8.1.1/api.html#ostream-api

API latest(v9) https://fmt.dev/latest/api.html#ostream-api

See also: https://devblogs.microsoft.com/cppblog/format-in-visual-studio-2019-version-16-10/#differences-from-fmt-not-exhaustive

But why C++std not to format by std::ostream<<?

Upvotes: 1

Mathias Rav
Mathias Rav

Reputation: 2973

By argument-dependent lookup, it's required to put the operator<< definition inside the foo namespace:

#include <fmt/format.h>
#include <fmt/ostream.h>

namespace foo {
struct A {};

std::ostream& operator<<(std::ostream& os, const A& a)
{
  return os << "A!";
}
} // namespace foo

int main()
{
  fmt::print("{}\n", foo::A{});
}

Upvotes: 8

Related Questions