diff --git a/include/fmt/format.h b/include/fmt/format.h index e1b27a3b..4fc6a538 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -1777,6 +1777,15 @@ OutputIt write(OutputIt out, const void* value) { return write_ptr(out, to_uintptr(value), nullptr); } +template +auto write(OutputIt out, const T& value) -> typename std::enable_if< + mapped_type_constant>::value == + type::custom_type, + OutputIt>::type { + basic_format_context ctx(out, {}, {}); + return formatter().format(value, ctx); +} + // An argument visitor that formats the argument and writes it via the output // iterator. It's a class and not a generic lambda for compatibility with C++11. template struct default_arg_formatter { diff --git a/test/format-test.cc b/test/format-test.cc index 22fd12be..8108992d 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1906,9 +1906,30 @@ TEST(FormatTest, DynamicFormatter) { "precision not allowed for this argument type"); } +namespace adl_test { +namespace fmt { +namespace detail { +struct foo {}; +template void write(OutputIt, foo) = delete; +} // namespace detail +} // namespace fmt +} // namespace adl_test + +FMT_BEGIN_NAMESPACE +template <> +struct formatter : formatter { + template + auto format(adl_test::fmt::detail::foo, FormatContext& ctx) + -> decltype(ctx.out()) { + return formatter::format("foo", ctx); + } +}; +FMT_END_NAMESPACE + TEST(FormatTest, ToString) { EXPECT_EQ("42", fmt::to_string(42)); EXPECT_EQ("0x1234", fmt::to_string(reinterpret_cast(0x1234))); + EXPECT_EQ("foo", fmt::to_string(adl_test::fmt::detail::foo())); } TEST(FormatTest, ToWString) { EXPECT_EQ(L"42", fmt::to_wstring(42)); }