diff --git a/include/fmt/core.h b/include/fmt/core.h index 6df2875a..5700c152 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -830,7 +830,8 @@ template struct string_value { template struct custom_value { using parse_context = basic_format_parse_context; const void* value; - void (*format)(const void* arg, parse_context& parse_ctx, Context& ctx); + void (*format)(const void* arg, + typename Context::parse_context_type& parse_ctx, Context& ctx); }; // A formatting argument value. @@ -890,9 +891,9 @@ template class value { private: // Formats an argument of a custom type, such as a user-defined class. template - static void format_custom_arg( - const void* arg, basic_format_parse_context& parse_ctx, - Context& ctx) { + static void format_custom_arg(const void* arg, + typename Context::parse_context_type& parse_ctx, + Context& ctx) { Formatter f; parse_ctx.advance_to(f.parse(parse_ctx)); ctx.advance_to(f.format(*static_cast(arg), ctx)); @@ -1061,7 +1062,7 @@ template class basic_format_arg { public: explicit handle(internal::custom_value custom) : custom_(custom) {} - void format(basic_format_parse_context& parse_ctx, + void format(typename Context::parse_context_type& parse_ctx, Context& ctx) const { custom_.format(custom_.value, parse_ctx, ctx); } @@ -1272,6 +1273,7 @@ template class basic_format_context { public: using iterator = OutputIt; using format_arg = basic_format_arg; + using parse_context_type = basic_format_parse_context; template using formatter_type = formatter; basic_format_context(const basic_format_context&) = delete; diff --git a/include/fmt/ostream.h b/include/fmt/ostream.h index c4831533..4526f523 100644 --- a/include/fmt/ostream.h +++ b/include/fmt/ostream.h @@ -9,9 +9,14 @@ #define FMT_OSTREAM_H_ #include + #include "format.h" FMT_BEGIN_NAMESPACE + +template class basic_printf_parse_context; +template class basic_printf_context; + namespace internal { template class formatbuf : public std::basic_streambuf { @@ -93,9 +98,9 @@ void format_value(buffer& buf, const T& value, locale_ref loc = locale_ref()) { formatbuf format_buf(buf); std::basic_ostream output(&format_buf); - #if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) +#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR) if (loc) output.imbue(loc.get()); - #endif +#endif output.exceptions(std::ios_base::failbit | std::ios_base::badbit); output << value; buf.resize(buf.size()); @@ -104,14 +109,32 @@ void format_value(buffer& buf, const T& value, // Formats an object of type T that has an overloaded ostream operator<<. template struct fallback_formatter::value>> - : formatter, Char> { - template - auto format(const T& value, Context& ctx) -> decltype(ctx.out()) { + : private formatter, Char> { + auto parse(basic_format_parse_context& ctx) -> decltype(ctx.begin()) { + return formatter, Char>::parse(ctx); + } + template >::value)> + auto parse(ParseCtx& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + + template + auto format(const T& value, basic_format_context& ctx) + -> OutputIt { basic_memory_buffer buffer; format_value(buffer, value, ctx.locale()); basic_string_view str(buffer.data(), buffer.size()); return formatter, Char>::format(str, ctx); } + template + auto format(const T& value, basic_printf_context& ctx) + -> OutputIt { + basic_memory_buffer buffer; + format_value(buffer, value, ctx.locale()); + return std::copy(buffer.begin(), buffer.end(), ctx.out()); + } }; } // namespace internal diff --git a/include/fmt/printf.h b/include/fmt/printf.h index a7902280..5e0c4810 100644 --- a/include/fmt/printf.h +++ b/include/fmt/printf.h @@ -189,6 +189,10 @@ using internal::printf; // For printing into memory_buffer. template class printf_arg_formatter; +template +class basic_printf_parse_context : public basic_format_parse_context { + using basic_format_parse_context::basic_format_parse_context; +}; template class basic_printf_context; /** @@ -324,6 +328,7 @@ template class basic_printf_context { using char_type = Char; using iterator = OutputIt; using format_arg = basic_format_arg; + using parse_context_type = basic_printf_parse_context; template using formatter_type = printf_formatter; private: @@ -331,7 +336,7 @@ template class basic_printf_context { OutputIt out_; basic_format_args args_; - basic_format_parse_context parse_ctx_; + parse_context_type parse_ctx_; static void parse_flags(format_specs& specs, const Char*& it, const Char* end); @@ -362,7 +367,7 @@ template class basic_printf_context { format_arg arg(int id) const { return args_.get(id); } - basic_format_parse_context& parse_context() { return parse_ctx_; } + parse_context_type& parse_context() { return parse_ctx_; } FMT_CONSTEXPR void on_error(const char* message) { parse_ctx_.on_error(message); diff --git a/test/core-test.cc b/test/core-test.cc index f19d0423..735fcde2 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -210,7 +210,8 @@ TEST(ArgTest, FormatArgs) { } struct custom_context { - typedef char char_type; + using char_type = char; + using parse_context_type = fmt::format_parse_context; template struct formatter_type { template diff --git a/test/format-test.cc b/test/format-test.cc index e9304cee..b0a8fc88 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -2259,8 +2259,9 @@ struct test_parse_context { }; struct test_context { - typedef char char_type; - typedef fmt::basic_format_arg format_arg; + using char_type = char; + using format_arg = fmt::basic_format_arg; + using parse_context_type = fmt::format_parse_context; template struct formatter_type { typedef fmt::formatter type; diff --git a/test/printf-test.cc b/test/printf-test.cc index 5aaa27b1..5ae8469d 100644 --- a/test/printf-test.cc +++ b/test/printf-test.cc @@ -502,9 +502,7 @@ TEST(PrintfTest, PrintfError) { TEST(PrintfTest, WideString) { EXPECT_EQ(L"abc", fmt::sprintf(L"%s", L"abc")); } TEST(PrintfTest, PrintfCustom) { - // The test is disabled for now because it requires decoupling - // fallback_formatter::format from format_context. - //EXPECT_EQ("abc", test_sprintf("%s", TestString("abc"))); + EXPECT_EQ("abc", test_sprintf("%s", TestString("abc"))); } TEST(PrintfTest, OStream) {