From fd8e243be25b5453aad5bb32eb7dd78ce6a1c0a4 Mon Sep 17 00:00:00 2001 From: Justin Riddell Date: Sun, 7 Jul 2024 17:25:54 +0100 Subject: [PATCH] Enable inheriting from formatter Fixes #4036 This formatter specialization with base::format means a class implicitly convertible to std::string_view will now be converted by this format function before being passed to the fmt::string_view format function. This wouldn't work previously as the compiler may only perform one implicit conversion, and we need 2 here (from our type, to std::string_view, to fmt::string_view). --- include/fmt/format.h | 12 +++++++++++- test/format-test.cc | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/include/fmt/format.h b/include/fmt/format.h index 7c2a19b4084de..d8ac67f5b6ce9 100644 --- a/include/fmt/format.h +++ b/include/fmt/format.h @@ -3990,13 +3990,23 @@ FMT_FORMAT_AS(long, detail::long_type); FMT_FORMAT_AS(unsigned long, detail::ulong_type); FMT_FORMAT_AS(Char*, const Char*); FMT_FORMAT_AS(std::nullptr_t, const void*); -FMT_FORMAT_AS(detail::std_string_view, basic_string_view); FMT_FORMAT_AS(void*, const void*); template class formatter, Char> : public formatter, Char> {}; +// Fixes issue #4036 +template +struct formatter, Char> + : public formatter, Char> { + auto format(const detail::std_string_view& value, + format_context& ctx) const -> decltype(ctx.out()) { + using base = formatter, Char>; + return base::format(value, ctx); + } +}; + template struct formatter : formatter, Char> {}; diff --git a/test/format-test.cc b/test/format-test.cc index a9ef19fc19c81..5477ecd257610 100644 --- a/test/format-test.cc +++ b/test/format-test.cc @@ -1650,6 +1650,20 @@ TEST(format_test, format_explicitly_convertible_to_std_string_view) { EXPECT_EQ("'foo'", fmt::format("{}", explicitly_convertible_to_std_string_view())); } + +struct convertible_to_std_string_view { + operator std::string_view() const noexcept { return "Hi there"; } +}; +FMT_BEGIN_NAMESPACE +template <> +class formatter + : public formatter {}; +FMT_END_NAMESPACE + +TEST(format_test, format_implicitly_convertible_and_inherits_string_view) { + static_assert(fmt::is_formattable{}); + EXPECT_EQ("Hi there", fmt::format("{}", convertible_to_std_string_view{})); +} #endif class Answer {};