From 1f1b50707c8f56095481e29594b0da24431f82d5 Mon Sep 17 00:00:00 2001 From: Victor Zverovich Date: Fri, 7 Feb 2020 18:47:48 -0800 Subject: [PATCH] Make formatter override implicit conversion to a C string --- include/fmt/core.h | 10 +++++----- test/core-test.cc | 15 +++++++++++++++ test/ostream-test.cc | 18 +++++------------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/include/fmt/core.h b/include/fmt/core.h index 6824c125..35c6414c 100644 --- a/include/fmt/core.h +++ b/include/fmt/core.h @@ -900,7 +900,8 @@ template struct arg_mapper { template , T>::value && - !is_string::value)> + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> FMT_CONSTEXPR basic_string_view map(const T& val) { return basic_string_view(val); } @@ -909,7 +910,8 @@ template struct arg_mapper { FMT_ENABLE_IF( std::is_constructible, T>::value && !std::is_constructible, T>::value && - !is_string::value && !has_formatter::value)> + !is_string::value && !has_formatter::value && + !has_fallback_formatter::value)> FMT_CONSTEXPR basic_string_view map(const T& val) { return std_string_view(val); } @@ -946,10 +948,8 @@ template struct arg_mapper { typename T, FMT_ENABLE_IF( !is_string::value && !is_char::value && - !std::is_constructible, T>::value && (has_formatter::value || - (has_fallback_formatter::value && - !std::is_constructible, T>::value)))> + has_fallback_formatter::value))> FMT_CONSTEXPR const T& map(const T& val) { return val; } diff --git a/test/core-test.cc b/test/core-test.cc index 8f233ece..6a7c0d3b 100644 --- a/test/core-test.cc +++ b/test/core-test.cc @@ -469,6 +469,10 @@ struct convertible_to_int { operator int() const { return 42; } }; +struct convertible_to_c_string { + operator const char*() const { return "foo"; } +}; + FMT_BEGIN_NAMESPACE template <> struct formatter { auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { @@ -478,10 +482,21 @@ template <> struct formatter { return std::copy_n("foo", 3, ctx.out()); } }; + +template <> struct formatter { + auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { + return ctx.begin(); + } + auto format(convertible_to_c_string, format_context& ctx) + -> decltype(ctx.out()) { + return std::copy_n("bar", 3, ctx.out()); + } +}; FMT_END_NAMESPACE TEST(CoreTest, FormatterOverridesImplicitConversion) { EXPECT_EQ(fmt::format("{}", convertible_to_int()), "foo"); + EXPECT_EQ(fmt::format("{}", convertible_to_c_string()), "bar"); } namespace my_ns { diff --git a/test/ostream-test.cc b/test/ostream-test.cc index 9944618e..d9329345 100644 --- a/test/ostream-test.cc +++ b/test/ostream-test.cc @@ -264,17 +264,13 @@ struct explicitly_convertible_to_string_like { } }; -TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) { - EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like())); -} - std::ostream& operator<<(std::ostream& os, explicitly_convertible_to_string_like) { return os << "bar"; } -TEST(FormatterTest, FormatExplicitlyConvertibleToStringLikeIgnoreInserter) { - EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like())); +TEST(FormatterTest, FormatExplicitlyConvertibleToStringLike) { + EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like())); } #ifdef FMT_USE_STRING_VIEW @@ -284,17 +280,13 @@ struct explicitly_convertible_to_std_string_view { } }; -TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) { - EXPECT_EQ("foo", fmt::format("{}", explicitly_convertible_to_string_like())); -} - std::ostream& operator<<(std::ostream& os, explicitly_convertible_to_std_string_view) { return os << "bar"; } -TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringViewIgnoreInserter) { - EXPECT_EQ("foo", - fmt::format("{}", explicitly_convertible_to_std_string_view())); +TEST(FormatterTest, FormatExplicitlyConvertibleToStdStringView) { + EXPECT_EQ("bar", fmt::format("{}", explicitly_convertible_to_string_like())); } + #endif // FMT_USE_STRING_VIEW