std::format不支持递归嵌套和运行时宽度参数,需手动全特化std::formatter并置于std命名空间头文件中;parse()须严格解析格式字符串并返回非法位置,format()用std::format_to组合输出。

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











