std::format不支持递归嵌套和运行时宽度参数,需手动全特化std::formatter并置于std命名空间头文件中;parse()须严格解析格式字符串并返回非法位置,format()用std::format_to组合输出。
std::format 本身不支持递归嵌套格式化,也不接受运行时变量作为宽度参数——所有“自动展开”或“{:>w}”写法都会编译失败。必须手动特化,且宽度、对齐、精度等动态控制必须靠提前解析并缓存,再在中组合使用。
std::formatter 全特化必须放在 std 命名空间里,且不能是偏特化
你写
是非法的:C++ 标准禁止对模板类做偏特化。只能写具体类型,比如
。
特化代码必须定义在头文件中,不能只放在
里——否则其他翻译单元调用
时看不到它
如果嵌套容器含自定义类型(如
),则
也必须有对应的
全特化
漏掉
模板参数(比如只写
)会导致重载决议失败,报错类似
parse() 必须严格解析,不能跳过非法字符
不是“我看看有没有支持的字段”,而是“我逐字检查,遇到第一个不认识的就停”。返回
表示全部合法;返回中间位置表示从那里开始非法——
会据此抛
。
想支持
和
?得手动识别
后的数字,并用
或
解析,不能只取单个字符
若用户写了
,必须停在
处返回对应迭代器,不能吞掉它然后假装成功
别手写
format() 里禁用 std::format,只用 std::format_to
在自定义
成员函数里调用
是高危操作:它会触发新一轮
查找,如果
类型也有特化,就可能无限实例化模板,导致编译卡死或 OOM。
C知道
CSDN推出的一款AI技术问答工具
下载
立即学习
“
C++免费学习笔记(深入)
”;
正确做法是统一用
,它把结果直接写入当前输出迭代器,不新建上下文
对子字段是基本类型(
、
)或已特化类型(
),都走这条路径,自动复用其
需要动态宽度?把解析出的
存为成员变量,然后拼成
字面量传给
——注意:这个拼接只在 format() 运行时做一次,不是模板参数
嵌套容器对齐与缩进必须手动控制输出节奏
标准库不提供缩进辅助、不自动换行、不识别
。所谓“美化”,全靠你在
里往
写空格、换行符和括号。
二维 vector 输出成带缩进的结构?外层循环每进一层,先写
+ 若干空格,再写
;内层同理;末尾补
想让每个元素右对齐到 6 字符宽?不能依赖
的自动行为——你要对每个
单独调用
不要用
或拼接
中转:会丢失所有格式控制(填充字符、对齐方向、精度),还多一次内存分配
最易被忽略的是:
和
的 const 正确性、
类型别名声明、以及所有模板特化必须在所有使用点可见——这三个点任一出错,都不会报“formatter 未定义”,而是静默退化成调用
std::formatterparse()format()std::format_totemplate struct std::formatter<:vector>, char> template struct std::formatter<:vector>>, char>.cppstd::formatstd::vectorPersonstd::formattercharstd::formatterno matching function for call to 'format'parse()ctx.end()std::formatstd::format_error{:indent=2}{:width=8}=std::from_charsstd::stoi{:width=8x}'x'*it >= '0' && *it 判断数字——宽字符下失效;用 std::isdigit(static_cast(*it)) format()std::format("{}", field)std::formatterfieldstd::format_to(ctx.out(), "{}", field)intdoublePersonformatterwidth_"{:" + std::to_string(width_) + "}"format_tostd::endlformat()ctx.out()"\n""[""]"{:>6}elemstd::format_to(out, "{:>6}", elem)std::ostringstreamstd::stringparse()format()char_typeoperator 或直接编译失败,调试成本极高。