From 020385386847cdd083651147783cc8fe0db05066 Mon Sep 17 00:00:00 2001 From: John Eivind Helset Date: Sat, 18 Jun 2022 16:53:00 +0200 Subject: [PATCH] Fix is_formattable for tuple-like types. --- include/fmt/ranges.h | 26 +++++++++++++++++++++++++- test/ranges-test.cc | 12 ++++++++++++ test/xchar-test.cc | 2 ++ 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index a1fc80d2..3290fbee 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -202,6 +202,24 @@ template using make_index_sequence = make_integer_sequence; #endif +template +using tuple_index_sequence = make_index_sequence>; + +template ::value> +struct is_tuple_formattable_ { + static constexpr const bool value = false; +}; +template struct is_tuple_formattable_ { + template + static std::integral_constant< + bool, (fmt::is_formattable>::value && ...)> + check(index_sequence); + + public: + static constexpr const bool value = + decltype(check(tuple_index_sequence{}))::value; +}; + template void for_each(index_sequence, Tuple&& tup, F&& f) noexcept { using std::get; @@ -283,8 +301,14 @@ template struct is_tuple_like { detail::is_tuple_like_::value && !detail::is_range_::value; }; +template struct is_tuple_formattable { + static constexpr const bool value = detail::is_tuple_formattable_::value; +}; + template -struct formatter::value>> { +struct formatter::value && + fmt::is_tuple_formattable::value>> { private: // C++11 generic lambda for format(). template struct format_each { diff --git a/test/ranges-test.cc b/test/ranges-test.cc index cdc6930d..ce6dc512 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -90,6 +90,18 @@ TEST(ranges_test, format_tuple) { std::tuple(42, 1.5f, "this is tuple", 'i'); EXPECT_EQ(fmt::format("{}", t), "(42, 1.5, \"this is tuple\", 'i')"); EXPECT_EQ(fmt::format("{}", std::tuple<>()), "()"); + + enum class noformatenum{b}; + struct noformatstruct{}; + EXPECT_TRUE((fmt::is_formattable>::value)); + EXPECT_FALSE((fmt::is_formattable::value)); + EXPECT_FALSE((fmt::is_formattable::value)); + EXPECT_FALSE((fmt::is_formattable>::value)); + EXPECT_FALSE((fmt::is_formattable>::value)); + EXPECT_FALSE((fmt::is_formattable>::value)); + EXPECT_FALSE((fmt::is_formattable>::value)); + EXPECT_FALSE((fmt::is_formattable>::value)); + EXPECT_TRUE((fmt::is_formattable>::value)); } #ifdef FMT_RANGES_TEST_ENABLE_FORMAT_STRUCT diff --git a/test/xchar-test.cc b/test/xchar-test.cc index 498ff651..95a9c0bd 100644 --- a/test/xchar-test.cc +++ b/test/xchar-test.cc @@ -315,10 +315,12 @@ TEST(xchar_test, ostream) { #endif } +#ifdef FMT_XCHAR_TEST_ENABLE_FORMAT_MAP TEST(xchar_test, format_map) { auto m = std::map{{L"one", 1}, {L"t\"wo", 2}}; EXPECT_EQ(fmt::format(L"{}", m), L"{\"one\": 1, \"t\\\"wo\": 2}"); } +#endif TEST(xchar_test, escape_string) { using vec = std::vector;