C++20 std::format自定义类型formatter适配long等类型编译报错求解
C++20 std::format泛型包装类型formatter通用实现
问题背景
cppreference给出的泛型包装类型Box的formatter特化示例采用公有继承std::formatter<T, CharT>的写法,仅在包装int等基础类型时可正常工作:
// 原示例代码 template<class T> struct Box { T value; }; template<class T, class CharT> struct std::formatter<Box<T>, CharT> : std::formatter<T, CharT> { template<class FormatContext> auto format(Box<T> t, FormatContext& fc) const { return std::formatter<T, CharT>::format(t.value, fc); } }; int main() { Box<int> v = { 42 }; std::cout << std::format("{:#x}", v); // 正常输出0x2a }
该实现存在明显缺陷:当包装类型为long等未被std::basic_format_arg特殊处理的类型时,代码会直接编译失败。将long强转int的hack方案不具备通用性,自行实现完整formatter时如果用std::basic_string缓存格式占位符,也会因为constexpr上下文不支持动态内存分配触发编译错误。
问题根因
编译失败来自两个核心问题:
- 公有继承
std::formatter<T, CharT>的写法,会让部分标准库实现的format参数检查逻辑,误将Box<T>识别为T类型做格式参数校验,当T不在std::basic_format_arg的默认支持类型列表中时直接报错 - 自行实现parse方法时手动解析、缓存格式串的写法,很容易违反constexpr求值规则,触发编译错误。
通用解决方案
采用成员持有底层formatter+全转发的实现方式,不需要继承基类、不需要手动解析格式串,可自动适配所有本身支持std::format格式化的被包装类型:
#include <format> #include <iostream> template<class T> struct Box { T value; }; // 通用formatter特化 template<class T, class CharT> struct std::formatter<Box<T>, CharT> { // 以成员变量方式持有底层类型的formatter,避免公有继承带来的类型检查误判 std::formatter<T, CharT> base_formatter; // parse方法完全转发给底层formatter处理,无需自行缓存格式说明符 template<class ParseContext> constexpr auto parse(ParseContext& ctx) { return base_formatter.parse(ctx); } // format方法转发包装内的值给底层formatter处理 template<class FormatContext> auto format(const Box<T>& box, FormatContext& ctx) const { return base_formatter.format(box.value, ctx); } }; int main() { // 测试long类型包装,支持所有格式说明符 Box<long> v1 = {42}; std::cout << std::format("默认格式:{},十六进制:{:#x}\n", v1, v1); // 自动适配其他可格式化类型,比如double Box<double> v2 = {3.1415926}; std::cout << std::format("保留两位小数:{:.2f}\n", v2); return 0; }
该实现的特性:
- 无硬编码类型转换逻辑,只要被包装类型
T本身实现了std::formatter特化,Box<T>就可以直接使用,自动继承T支持的所有格式说明符(对齐、宽度、精度、进制、填充等) - parse逻辑完全复用底层formatter的实现,不需要手动解析格式串,也没有动态内存分配操作,完全符合constexpr要求
- 兼容GCC libstdc++、Clang libc++、MSVC STL等所有主流标准库的C++20 format实现,无编译兼容性问题。
内容的提问来源于stack exchange,提问作者gast128
相关产品推荐
相关产品推荐

