From 7d4f1d6afc55510cae3ac1e860a0f0d2568a9d0a Mon Sep 17 00:00:00 2001 From: Vladislav Shchapov Date: Thu, 30 Apr 2026 23:21:03 +0500 Subject: [PATCH] Fix ambiguous formatter> between fmt/std.h and fmt/ranges.h on C++26 (P3168R2) Signed-off-by: Vladislav Shchapov --- include/fmt/ranges.h | 12 ++++++++++-- test/ranges-test.cc | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/include/fmt/ranges.h b/include/fmt/ranges.h index d7dbc168..6ce57f5e 100644 --- a/include/fmt/ranges.h +++ b/include/fmt/ranges.h @@ -129,6 +129,13 @@ template class is_tuple_like_ { !std::is_void(nullptr))>::value; }; +template +struct is_optional_like_ : std::false_type {}; +template +struct is_optional_like_().has_value()), + decltype(std::declval().value())>> + : std::true_type {}; + // Check for integer_sequence #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900 template @@ -343,8 +350,9 @@ struct formatter struct is_range { - static constexpr bool value = - detail::is_range_::value && !detail::has_to_string_view::value; + static constexpr bool value = detail::is_range_::value && + !detail::is_optional_like_::value && + !detail::has_to_string_view::value; }; namespace detail { diff --git a/test/ranges-test.cc b/test/ranges-test.cc index bd161d75..4afd6c72 100644 --- a/test/ranges-test.cc +++ b/test/ranges-test.cc @@ -271,6 +271,23 @@ TEST(ranges_test, disabled_range_formatting_of_path) { fmt::range_format::disabled); } +template struct optional_like { + auto begin() const -> const T*; + auto end() const -> const T*; + + bool has_value() const noexcept; + T& value() &; + const T& value() const&; + T&& value() &&; + const T&& value() const&&; +}; + +TEST(ranges_test, disabled_range_formatting_of_optional) { + // (C++26) Has a range support for std::optional. + EXPECT_EQ((fmt::range_format_kind, char>::value), + fmt::range_format::disabled); +} + struct vector_string : std::vector { using base = std::vector; using base::base;