Closed mattgodbolt closed 1 month ago
@vitaut suggests a workaround of:
template <>
struct fmt::is_range<cstring_view, char> : std::false_type {};
Closing as the ambiguity is legit: there are two formatters, one for a range and one defined via format_as
, and there is already a trait to opt out of the range formatting.
The big advantage of format_as
is that we can use it in library code to make our types "{fmt} friendly", without needing to add a dependency on {fmt}. As soon as we need to start providing specializations of types in the fmt
namespace then we have to include {fmt} headers.
Given that including fmt/ranges.h
can silently change the way that other code formats things, if I include fmt/ranges.h
in my library header in order to specialize fmt::is_range
(even if wrapped in a __has_include
check), then someone depending on my library might silently get different formatting behaviour for their other types.
I understand that there is an ambiguity if there are two different formatters available for a type. But there is an inconsistency in the rules, isn't there?
fmt::format
specialization and a format_as
overload for a type.format_as
overload for a type that is a range (in case someone includes fmt/ranges.h
)fmt::format
specialization for a type that is a range. It will always get used in preference to the range formatter.If someone has gone to the effort of adding a format_as
overload for a type, shouldn't it take precedence over an implicit range formatter?
Given that including fmt/ranges.h can silently change the way that other code formats things...
To be clear, I don't believe that's possible any more, but it was possible with earlier versions of {fmt} for types that were ranges and also had a stream insertion operator. My point is that I don't know what version of {fmt} consumers of my library will be using, so I want to minimize the possibility that I might change the behaviour of their code unexpectedly. That's why providing a simple format_as
overload is so appealing.
format_as
is just a way to define a formatter
(with a potential optimization at the call site) so it should be consistent. In both cases you have to opt out of range formatting if you want to customize formatting of a range.
If we use a
format_as
for a range-like object, we get a compile error _if we include<fmt/ranges.h>
only. This didn't happen in fmt 9.x but does in 10.x and newer.https://compiler-explorer.com/z/97s7hcK4j
The error seems to be:
though it's hard to tell :)
Is there a way to tell
fmt
to "shoo, this isn't a range you should use" ?CC @jeremy-rifkin @apmorton