Fix ambiguous formatter<std::optional<T>> between fmt/std.h and fmt/ranges.h on C++26 (P3168R2) (#4761)

Signed-off-by: Vladislav Shchapov <vladislav@shchapov.ru>
This commit is contained in:
Vladislav Shchapov 2026-05-03 19:37:46 +05:00 committed by GitHub
parent 5a9a184448
commit 9cb8c0f92b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 27 additions and 2 deletions

View File

@ -129,6 +129,13 @@ template <typename T> class is_tuple_like_ {
!std::is_void<decltype(check<T>(nullptr))>::value;
};
template <typename T, typename _ = void>
struct is_optional_like_ : std::false_type {};
template <typename T>
struct is_optional_like_<T, void_t<decltype(std::declval<T>().has_value()),
decltype(std::declval<T>().value())>>
: std::true_type {};
// Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
template <typename T, T... N>
@ -343,8 +350,9 @@ struct formatter<Tuple, Char,
FMT_EXPORT
template <typename T, typename Char> struct is_range {
static constexpr bool value =
detail::is_range_<T>::value && !detail::has_to_string_view<T>::value;
static constexpr bool value = detail::is_range_<T>::value &&
!detail::is_optional_like_<T>::value &&
!detail::has_to_string_view<T>::value;
};
namespace detail {

View File

@ -271,6 +271,23 @@ TEST(ranges_test, disabled_range_formatting_of_path) {
fmt::range_format::disabled);
}
template <typename T> 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<optional_like<int>, char>::value),
fmt::range_format::disabled);
}
struct vector_string : std::vector<char> {
using base = std::vector<char>;
using base::base;