Skip to content

Commit 9cb8c0f

Browse files
authored
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>
1 parent 5a9a184 commit 9cb8c0f

2 files changed

Lines changed: 27 additions & 2 deletions

File tree

include/fmt/ranges.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ template <typename T> class is_tuple_like_ {
129129
!std::is_void<decltype(check<T>(nullptr))>::value;
130130
};
131131

132+
template <typename T, typename _ = void>
133+
struct is_optional_like_ : std::false_type {};
134+
template <typename T>
135+
struct is_optional_like_<T, void_t<decltype(std::declval<T>().has_value()),
136+
decltype(std::declval<T>().value())>>
137+
: std::true_type {};
138+
132139
// Check for integer_sequence
133140
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VERSION >= 1900
134141
template <typename T, T... N>
@@ -343,8 +350,9 @@ struct formatter<Tuple, Char,
343350

344351
FMT_EXPORT
345352
template <typename T, typename Char> struct is_range {
346-
static constexpr bool value =
347-
detail::is_range_<T>::value && !detail::has_to_string_view<T>::value;
353+
static constexpr bool value = detail::is_range_<T>::value &&
354+
!detail::is_optional_like_<T>::value &&
355+
!detail::has_to_string_view<T>::value;
348356
};
349357

350358
namespace detail {

test/ranges-test.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,23 @@ TEST(ranges_test, disabled_range_formatting_of_path) {
271271
fmt::range_format::disabled);
272272
}
273273

274+
template <typename T> struct optional_like {
275+
auto begin() const -> const T*;
276+
auto end() const -> const T*;
277+
278+
bool has_value() const noexcept;
279+
T& value() &;
280+
const T& value() const&;
281+
T&& value() &&;
282+
const T&& value() const&&;
283+
};
284+
285+
TEST(ranges_test, disabled_range_formatting_of_optional) {
286+
// (C++26) Has a range support for std::optional.
287+
EXPECT_EQ((fmt::range_format_kind<optional_like<int>, char>::value),
288+
fmt::range_format::disabled);
289+
}
290+
274291
struct vector_string : std::vector<char> {
275292
using base = std::vector<char>;
276293
using base::base;

0 commit comments

Comments
 (0)