Fmt 11.1.0 added a formatter specialization for std::reference_wrapper<T>.
|
template <typename T, typename Char> |
|
struct formatter<std::reference_wrapper<T>, Char, |
|
enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>> |
|
: formatter<remove_cvref_t<T>, Char> { |
|
template <typename FormatContext> |
|
auto format(std::reference_wrapper<T> ref, FormatContext& ctx) const |
|
-> decltype(ctx.out()) { |
|
return formatter<remove_cvref_t<T>, Char>::format(ref.get(), ctx); |
|
} |
|
}; |
This can result in errors due to ambiguous templates when T can be used with format_as:
#include <fmt/format.h>
#include <fmt/std.h>
#include <functional>
struct S {
int x;
};
int format_as(S);
int main() {
S s;
fmt::format("{}", std::ref(s));
}
<source>:14:16: in 'constexpr' expansion of 'fmt::v11::fstring<std::reference_wrapper<S> >("{}")'
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/base.h:1119:52: error: ambiguous template instantiation for 'struct fmt::v11::formatter<std::reference_wrapper<S>, char, void>'
1119 | remove_cvref_t<decltype(formatter<T>::format_as(std::declval<const T&>()))>;
| ~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/format.h:3810:8: note: candidates are: 'template<class T, class Char> struct fmt::v11::formatter<T, Char, fmt::v11::void_t<typename std::remove_cv<typename std::remove_reference<decltype (format_as(declval<const T&>()))>::type>::type> > [with T = std::reference_wrapper<S>; Char = char]'
3810 | struct formatter<T, Char, void_t<detail::format_as_result<T>>>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from <source>:2:
/opt/compiler-explorer/libs/fmt/trunk/include/fmt/std.h:699:8: note: 'template<class T, class Char> struct fmt::v11::formatter<std::reference_wrapper<_Tp>, Char, typename std::enable_if<std::integral_constant<bool, (! std::is_same<decltype (fmt::v11::detail::type_mapper<Char>::map(declval<typename std::conditional<std::is_void<typename std::remove_cv<typename std::remove_reference<_Tp>::type>::type>::value, int*, typename std::remove_cv<typename std::remove_reference<_Tp>::type>::type>::type&>())), void>::value)>::value, void>::type> [with T = S; Char = char]'
699 | struct formatter<std::reference_wrapper<T>, Char,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
700 | enable_if_t<is_formattable<remove_cvref_t<T>, Char>::value>>
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
https://godbolt.org/z/r71vbP4KG
This is an unfortunate consequence of std::reference_wrapper having a non-explicit operator T& which allows a call like format_as(std::ref(s)) to be valid.
Repro without fmt/std.h, manually providing the specialization: https://godbolt.org/z/TeeP49x95.
I can think of two possible solutions, I'm sure more exist:
One possible solution is to embrace format_as instead of specializing fmt::formatter for this:
template <typename T>
T& format_as(std::reference_wrapper<T>);
This solves the problem as naturally int format_as(S); is a better match https://godbolt.org/z/h173rEa6q
Another possible solution is to constrain fmt::formatter<std::reference_wrapper<T>> to types T which are not format_as-ible https://godbolt.org/z/j66Ko5Tzq.
Fmt 11.1.0 added a formatter specialization for
std::reference_wrapper<T>.fmt/include/fmt/std.h
Lines 698 to 707 in c792524
This can result in errors due to ambiguous templates when
Tcan be used withformat_as:https://godbolt.org/z/r71vbP4KG
This is an unfortunate consequence of
std::reference_wrapperhaving a non-explicitoperator T&which allows a call likeformat_as(std::ref(s))to be valid.Repro without
fmt/std.h, manually providing the specialization: https://godbolt.org/z/TeeP49x95.I can think of two possible solutions, I'm sure more exist:
One possible solution is to embrace
format_asinstead of specializingfmt::formatterfor this:This solves the problem as naturally
int format_as(S);is a better match https://godbolt.org/z/h173rEa6qAnother possible solution is to constrain
fmt::formatter<std::reference_wrapper<T>>to typesTwhich are notformat_as-ible https://godbolt.org/z/j66Ko5Tzq.