自定义boost::system::error_code格式化器时GCC/clang报左大括号不匹配错误?
自定义boost::system::error_code formatter编译失败问题
我为boost::system::error_code定义了一个自定义std::formatter特化,但当格式字符串中替换字段{}前存在其他文本时,GCC和Clang都会编译失败。
涉及代码
#include <iostream> #include <format> #include <boost/system/error_code.hpp> template<> struct std::formatter<boost::system::error_code, char> { constexpr auto parse(auto &ctx) { return ctx.end(); } auto format(const boost::system::error_code &ec, auto &ctx) const { return std::format_to(ctx.out(), "{}", ec.message()); } }; int main() { std::cout << std::format("{}", boost::system::error_code()) << std::endl; std::cout << std::format(" {}", boost::system::error_code()) << std::endl; }
GCC错误信息
<source>: In function 'int main()': <source>:22:29: error: call to consteval function 'std::basic_format_string<char, boost::system::error_code>(" {}")' is not a constant expression 22 | std::cout << std::format(" {}", boost::system::error_code()) << std::endl; | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In file included from <source>:2: <source>:22:29: in 'constexpr' expansion of 'std::basic_format_string<char, boost::system::error_code>(" {}")' /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/format:4208:19: in 'constexpr' expansion of '__scanner.std::__format::_Checking_scanner<char, boost::system::error_code>::std::__format::_Scanner<char>.std::__format::_Scanner<char>::_M_scan()' /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/format:3949:30: in 'constexpr' expansion of '((std::__format::_Scanner<char>*)this)->std::__format::_Scanner<char>::_M_on_replacement_field()' /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/format:4003:60: error: call to non-'constexpr' function 'void std::__format::__unmatched_left_brace_in_format_string()' 4003 | __format::__unmatched_left_brace_in_format_string(); | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~ /opt/compiler-explorer/gcc-14.2.0/include/c++/14.2.0/format:203:3: note: 'void std::__format::__unmatched_left_brace_in_format_string()' declared here 203 | __unmatched_left_brace_in_format_string() | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Clang错误信息
<source>:22:30: error: call to consteval function 'std::basic_format_string<char, boost::system::error_code>::basic_format_string<char[4]>' is not a constant expression 22 | std::cout << std::format(" {}", boost::system::error_code()) << std::endl; | ^ /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../include/c++/15.0.0/format:4120:4: note: non-constexpr function '__unmatched_left_brace_in_format_string' cannot be used in a constant expression 4120 | __format::__unmatched_left_brace_in_format_string(); | ^ /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../include/c++/15.0.0/format:4066:7: note: in call to 'this->_M_on_replacement_field()' 4066 | _M_on_replacement_field(); | ^~~~~~~~~~~~~~~~~~~~~~~~~ /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../include/c++/15.0.0/format:4377:2: note: in call to '__scanner._M_scan()' 4377 | __scanner._M_scan(); | ^~~~~~~~~~~~~~~~~~~ <source>:22:30: note: in call to 'basic_format_string<char[4]>(" {}")' 22 | std::cout << std::format(" {}", boost::system::error_code()) << std::endl; | ^~~~~ /opt/compiler-explorer/gcc-snapshot/lib/gcc/x86_64-linux-gnu/15.0.0/../../../../include/c++/15.0.0/format:209:3: note: declared here 209 | __unmatched_left_brace_in_format_string() | ^
问题原因与修复
这是你的代码存在问题,问题出在formatter的parse方法实现上。
C++标准要求,std::formatter的parse方法必须正确解析格式字符串中替换字段内的格式说明符部分——即使你不需要任何格式参数,也需要正确消耗掉闭合大括号}。你的parse方法直接返回ctx.end(),这会让格式字符串扫描器认为你没有处理完替换字段的内容,当格式字符串前有其他文本时,扫描器会误判为存在不匹配的左大括号,从而触发编译期错误。
修复后的代码如下:
#include <iostream> #include <format> #include <boost/system/error_code.hpp> template<> struct std::formatter<boost::system::error_code, char> { constexpr auto parse(auto &ctx) { auto it = ctx.begin(); // 跳过闭合大括号,表明已处理完格式说明部分 if (it != ctx.end() && *it == '}') { ++it; } return it; } auto format(const boost::system::error_code &ec, auto &ctx) const { return std::format_to(ctx.out(), "{}", ec.message()); } }; int main() { std::cout << std::format("{}", boost::system::error_code()) << std::endl; std::cout << std::format(" {}", boost::system::error_code()) << std::endl; }
这个修复让parse方法正确识别并跳过替换字段的闭合大括号,告诉格式字符串扫描器已经处理完当前替换字段的格式说明部分,扫描器就能正确解析格式字符串中的其他内容,不会再触发不匹配大括号的错误。
内容的提问来源于stack exchange,提问作者climb4
相关产品推荐
相关产品推荐

