mirror of
https://github.com/fmtlib/fmt.git
synced 2025-06-25 09:21:41 +02:00
Fix reference_wrapper ambiguity with format_as (#4434)
This commit is contained in:
@ -678,9 +678,28 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
|
||||
}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_format_as : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_format_as<T, void_t<decltype(format_as(std::declval<const T&>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct has_format_as_member : std::false_type {};
|
||||
template <typename T>
|
||||
struct has_format_as_member<
|
||||
T, void_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>>
|
||||
: std::true_type {};
|
||||
} // namespace detail
|
||||
|
||||
// Guard against format_as because reference_wrappers are implicitly convertible
|
||||
// to T&
|
||||
template <typename T, typename Char>
|
||||
struct formatter<std::reference_wrapper<T>, Char,
|
||||
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>>
|
||||
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value &&
|
||||
!detail::has_format_as<T>::value &&
|
||||
!detail::has_format_as_member<T>::value>>
|
||||
: formatter<remove_cvref_t<T>, Char> {
|
||||
template <typename FormatContext>
|
||||
auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const
|
||||
|
@ -414,4 +414,36 @@ TEST(std_test, format_shared_ptr) {
|
||||
TEST(std_test, format_reference_wrapper) {
|
||||
int num = 35;
|
||||
EXPECT_EQ("35", fmt::to_string(std::cref(num)));
|
||||
EXPECT_EQ("35", fmt::to_string(std::ref(num)));
|
||||
EXPECT_EQ("35", fmt::format("{}", std::cref(num)));
|
||||
EXPECT_EQ("35", fmt::format("{}", std::ref(num)));
|
||||
}
|
||||
|
||||
// Regression test for https://github.com/fmtlib/fmt/issues/4424
|
||||
struct type_with_format_as {
|
||||
int x;
|
||||
};
|
||||
|
||||
int format_as(const type_with_format_as& t) { return t.x; }
|
||||
|
||||
TEST(std_test, format_reference_wrapper_with_format_as) {
|
||||
type_with_format_as t{20};
|
||||
EXPECT_EQ("20", fmt::to_string(std::cref(t)));
|
||||
EXPECT_EQ("20", fmt::to_string(std::ref(t)));
|
||||
EXPECT_EQ("20", fmt::format("{}", std::cref(t)));
|
||||
EXPECT_EQ("20", fmt::format("{}", std::ref(t)));
|
||||
}
|
||||
|
||||
struct type_with_format_as_string {
|
||||
std::string str;
|
||||
};
|
||||
|
||||
std::string format_as(const type_with_format_as_string& t) { return t.str; }
|
||||
|
||||
TEST(std_test, format_reference_wrapper_with_format_as_string) {
|
||||
type_with_format_as_string t{"foo"};
|
||||
EXPECT_EQ("foo", fmt::to_string(std::cref(t)));
|
||||
EXPECT_EQ("foo", fmt::to_string(std::ref(t)));
|
||||
EXPECT_EQ("foo", fmt::format("{}", std::cref(t)));
|
||||
EXPECT_EQ("foo", fmt::format("{}", std::ref(t)));
|
||||
}
|
||||
|
Reference in New Issue
Block a user