如何为fmt库添加格式说明符实现整数十六进制与十进制双输出?
为fmt库添加整数双格式(十六进制+十进制)的格式说明符
希望为fmt库添加一个格式说明符,让整数同时以十六进制和十进制形式输出(例如"0xff (255)")。尝试通过自定义整数别名myint = uint64_t并特化fmt::formatter的方法失败,代码如下:
using myint = uint64_t; template <> struct fmt::formatter<myint> { constexpr auto parse(format_parse_context& ctx) -> decltype(ctx.begin()) { auto it = ctx.begin(), end = ctx.end(); if(it != end && *it == 'z') it++; return it; } template <typename FormatContext> auto format(const myint& p, FormatContext& ctx) const -> decltype(ctx.out()) { return fmt::format_to(ctx.out(), "z: {:x} {}", p, p); } };
请问还有其他可行的实现方法吗?
可行解决方案
核心原因说明
你的代码失效是因为myint只是uint64_t的类型别名,并非全新的自定义类型。fmt库已经内置了针对uint64_t的formatter特化,自定义别名的特化会被视为重复定义而被忽略,无法覆盖内置行为。必须通过全新的包装类型来实现自定义格式化逻辑。
方法1:自定义包装器类型 + 特化fmt::formatter
创建一个专门的包装类型来包裹整数,然后为这个类型特化fmt::formatter,这样就能实现自定义的双格式输出:
#include <fmt/core.h> // 自定义包装类型,用于标记需要双格式输出的整数 struct HexDec { uint64_t value; }; // 为HexDec类型特化fmt::formatter template <> struct fmt::formatter<HexDec> { // 解析格式说明符(可选支持自定义标记,比如示例中的'z') constexpr auto parse(format_parse_context& ctx) { auto it = ctx.begin(); // 可自定义解析格式标记,比如识别'z' if (it != ctx.end() && *it == 'z') { ++it; } // 校验格式说明符的合法性,避免多余字符 if (it != ctx.end() && *it != '}') { throw fmt::format_error("invalid format specifier for HexDec"); } return it; } // 实现格式化逻辑:输出十六进制+十进制 template <typename FormatContext> auto format(const HexDec& hd, FormatContext& ctx) const { return fmt::format_to(ctx.out(), "0x{:x} ({})", hd.value, hd.value); } }; // 使用示例 int main() { uint64_t num = 255; fmt::print("{}", HexDec{num}); // 输出:0xff (255) fmt::print("{:z}", HexDec{num}); // 支持自定义标记(可根据需求调整format逻辑) }
方法2:利用fmt的format_as自定义点
如果不需要复杂的格式说明符解析,可以用format_as简化实现,它是fmt提供的用于自定义类型格式化的便捷接口:
#include <fmt/core.h> struct HexDecWrap { uint64_t value; }; // 实现format_as,返回预格式化的字符串 template <typename T> auto format_as(const HexDecWrap& hd) { return fmt::format("0x{:x} ({})", hd.value, hd.value); } // 使用示例 int main() { fmt::print("{}", HexDecWrap{255}); // 输出:0xff (255) }
方法3:直接使用自定义格式化函数
如果不需要通过格式说明符触发,也可以直接写一个工具函数来生成双格式字符串:
#include <fmt/core.h> #include <string> template <typename IntegerType> std::string format_hex_dec(IntegerType num) { static_assert(std::is_integral_v<IntegerType>, "must be integer type"); return fmt::format("0x{:x} ({})", num, num); } // 使用示例 int main() { fmt::print("{}", format_hex_dec(255)); // 输出:0xff (255) fmt::print("{}", format_hex_dec(100)); // 输出:0x64 (100) }
内容的提问来源于stack exchange,提问作者bernd feinman
相关产品推荐
相关产品推荐

