Reputation: 5813
I am about to switch from C++20 to C++23, which has std::formattable
.
In C++20, I had used the formattable
from https://stackoverflow.com/a/72430675, but it turns out std::formattable
works differently. In effect, classes that are formattable
are not necessarily std::formattable
, and I wonder why. Here's one example:
#include <format>
#include <string>
#include <type_traits>
enum class RandomEnum { A, B };
// Formatter that formats everything as "ABC"
template <>
struct std::formatter<RandomEnum> : std::formatter<std::string> {
auto format(const RandomEnum t, std::format_context& ctx) const {
return std::formatter<std::string>::format("ABC", ctx);
}
};
// Pre-C++23 version of std::formattable
template <typename T>
concept formattable = requires(T& v, std::format_context ctx) {
std::formatter<std::remove_cvref_t<T>>().format(v, ctx);
};
int main() {
// Returns 2: class is formattable but not std::formattable:
return (formattable<RandomEnum> << 1) + std::formattable<RandomEnum, char>;
}
How can I make my enum classes std::formattable
?
This code examples gives an error message in MSVC and clang, but that doesn't help me much, either:
#include <format>
#include <string>
#include <type_traits>
enum class RandomEnum { A, B };
template <>
struct std::formatter<RandomEnum> : std::formatter<std::string> {
auto format(const RandomEnum t, std::format_context& ctx) const {
return std::formatter<std::string>::format("ABC", ctx);
}
};
int fun(std::formattable<char> auto x) { return 0; }
int main() { return fun(RandomEnum::A); }
MSVC:
<source>(16): error C2672: 'fun': no matching overloaded function found
<source>(14): note: could be 'int fun(_T0)'
<source>(16): note: the associated constraints are not satisfied
<source>(14): note: the concept 'std::formattable<RandomEnum,char>' evaluated to false
Z:/compilers/msvc/14.41.33923-14.41.33923.0/include\format(2255): note: the concept 'std::_Formattable_with<RandomEnum,std::basic_format_context<std::_Phony_fmt_iter_for<char>,char>,std::formatter<RandomEnum,char>>' evaluated to false
Z:/compilers/msvc/14.41.33923-14.41.33923.0/include\format(658): note: 'std::back_insert_iterator<std::_Fmt_buffer<char>> std::formatter<RandomEnum,char>::format(const RandomEnum,std::format_context &) const': cannot convert argument 2 from 'std::basic_format_context<std::_Phony_fmt_iter_for<char>,char>' to 'std::format_context &'
Z:/compilers/msvc/14.41.33923-14.41.33923.0/include\format(658): note: while trying to match the argument list '(RandomEnum, std::basic_format_context<std::_Phony_fmt_iter_for<char>,char>)'
clang:
<source>:16:21: error: no matching function for call to 'fun'
16 | int main() { return fun(RandomEnum::A); }
| ^~~
<source>:14:5: note: candidate template ignored: constraints not satisfied [with x:auto = RandomEnum]
14 | int fun(std::formattable<char> auto x) { return 0; }
| ^
<source>:14:9: note: because 'std::formattable<RandomEnum, char>' evaluated to false
14 | int fun(std::formattable<char> auto x) { return 0; }
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2548:9: note: because '__format::__formattable_impl<remove_reference_t<RandomEnum>, char>' evaluated to false
2548 | = __format::__formattable_impl<remove_reference_t<_Tp>, _CharT>;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2539:43: note: because '__formattable_with<RandomEnum, std::basic_format_context<std::back_insert_iterator<std::basic_string<char> >, char> >' evaluated to false
2539 | = __parsable_with<_Tp, _Context> && __formattable_with<_Tp, _Context>;
| ^
/opt/compiler-explorer/gcc-14.2.0/lib/gcc/x86_64-linux-gnu/14.2.0/../../../../include/c++/14.2.0/format:2529:26: note: because '__cf.format(__t, __fc)' would be invalid: non-const lvalue reference to type 'basic_format_context<<U+007F>_Sink_iter<char><U+007F>, [...]>' cannot bind to a value of unrelated type 'basic_format_context<<U+007F>std::back_insert_iterator<std::basic_string<char>><U+007F>, [...]>'
2529 | { __cf.format(__t, __fc) } -> same_as<typename _Context::iterator>;
| ^
1 error generated.
Upvotes: 2
Views: 112