自定义fmt::formatter<std::bitset<N>>特化时出现-Wstringop-overflow编译警告
修复std::bitset的fmt::formatter特化编译警告
问题背景
尝试为std::bitset类创建fmt::formatter的特化版本,为了省去实现parse方法的麻烦,选择继承fmt::formatter<const char*>,但编译时GCC抛出了-Wstringop-overflow=的溢出警告。而在未继承基类、自行实现parse方法时,并没有这个警告。
原代码如下:
#include <bitset> #include <cstddef> #include <fmt/core.h> template <std::size_t N> struct fmt::formatter< std::bitset<N> > : fmt::formatter< const char* > { /* constexpr auto parse( format_parse_context& ctx ) { return ctx.begin( ); }*/ template <typename FormatContext> auto format( const std::bitset<N>& value, FormatContext& ctx ) { return fmt::format_to( ctx.out( ), "{}", value.to_string( ) ); } }; int main( ) { std::bitset<8> bitset1 { 0b01010101 }; fmt::print( "bitset1: {}\n", bitset1 ); }
编译时的警告信息:
warning: writing 1 byte into a region of size 0 [-Wstringop-overflow=]
原因分析
继承fmt::formatter<const char*>后,基类的parse方法会按照C字符串的格式规则去解析格式说明符,但你的format方法实际输出的是std::string对象的内容,二者底层的处理逻辑不匹配,导致编译器误判存在缓冲区溢出风险。
修复方案
方案1:自行实现parse方法
取消注释原有的parse方法,让特化类独立处理格式解析,避免基类的逻辑干扰:
#include <bitset> #include <cstddef> #include <fmt/core.h> template <std::size_t N> struct fmt::formatter< std::bitset<N> > : fmt::formatter< const char* > { constexpr auto parse( format_parse_context& ctx ) { return ctx.begin( ); } template <typename FormatContext> auto format( const std::bitset<N>& value, FormatContext& ctx ) { return fmt::format_to( ctx.out( ), "{}", value.to_string( ) ); } }; int main( ) { std::bitset<8> bitset1 { 0b01010101 }; fmt::print( "bitset1: {}\n", bitset1 ); }
方案2:匹配正确的基类特化
因为你的format方法最终输出的是std::string,直接继承fmt::formatter<std::string>更符合逻辑,能彻底消除警告:
#include <bitset> #include <cstddef> #include <fmt/core.h> template <std::size_t N> struct fmt::formatter< std::bitset<N> > : fmt::formatter< std::string > { template <typename FormatContext> auto format( const std::bitset<N>& value, FormatContext& ctx ) { return fmt::formatter<std::string>::format(value.to_string(), ctx); } }; int main( ) { std::bitset<8> bitset1 { 0b01010101 }; fmt::print( "bitset1: {}\n", bitset1 ); }
方案3:简化独立实现
如果不需要支持自定义格式说明符,也可以完全不继承任何基类,直接实现最基础的formatter特化:
#include <bitset> #include <cstddef> #include <fmt/core.h> template <std::size_t N> struct fmt::formatter<std::bitset<N>> { constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); } template <typename FormatContext> auto format(const std::bitset<N>& value, FormatContext& ctx) { return fmt::format_to(ctx.out(), "{}", value.to_string()); } }; int main( ) { std::bitset<8> bitset1 { 0b01010101 }; fmt::print( "bitset1: {}\n", bitset1 ); }
内容的提问来源于stack exchange,提问作者digito_evo
相关产品推荐
相关产品推荐

