如何让枚举类满足C++23的std::formattable概念?
问题
从C20切换到C23时,发现原本适配自定义formattable概念的枚举类无法满足std::formattable。示例代码中,自定义formattable<RandomEnum>为真,但std::formattable<RandomEnum, char>为假,导致无法使用std::formattable约束的函数。
原因
你的std::formatter<RandomEnum>的format函数参数固定为std::format_context&,但std::formattable概念会用**不同迭代器类型的std::basic_format_context**做校验(比如MSVC的std::basic_format_context<std::_Phony_fmt_iter_for<char>,char>、Clang的std::basic_format_context<std::back_insert_iterator<std::basic_string<char>>, char>)。
std::format_context是std::basic_format_context的特定迭代器特化,不同迭代器的basic_format_context属于完全不同的类型,无法绑定到固定的std::format_context&参数上,因此std::formattable校验失败。而你之前的C20自定义formattable仅用std::format_context做检查,所以能通过,但不符合C23标准的要求。
解决办法
修改formatter的format函数,使其接受任意类型的basic_format_context:
方案1:模板化FormatContext
#include <format> #include <string> enum class RandomEnum { A, B }; template <> struct std::formatter<RandomEnum> : std::formatter<std::string> { template <typename FormatContext> auto format(const RandomEnum, FormatContext& 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); }
方案2:显式指定字符类型并使用basic_format_context
#include <format> #include <string> enum class RandomEnum { A, B }; template <> struct std::formatter<RandomEnum, char> : std::formatter<std::string, char> { template <typename OutputIt> auto format(const RandomEnum, std::basic_format_context<OutputIt, char>& ctx) const { return std::formatter<std::string, char>::format("ABC", ctx); } }; int fun(std::formattable<char> auto x) { return 0; } int main() { return fun(RandomEnum::A); }
修改后,std::formattable<RandomEnum, char>会正确返回true,代码可通过MSVC和Clang编译。
内容的提问来源于stack exchange,提问作者bers

