必须手动为嵌套类型全特化std::formatter,标准库不提供;需在头文件中用template<> struct std::formatter<T>语法实现parse()和format(),后者用std::format_to递归格式化。

你想让 C++20 的 std::format 直接输出 std::vector<:vector>>{{1,2},{3,4,5}}</:vector> 这样的嵌套结构,而不是编译报错或打印一串地址,就必须手动为每种嵌套类型提供全特化 formatter——标准库不提供、编译器不会推导、头文件加再多也没用,这是 C++20 的硬性限制。
为二维 vector 全特化 std::formatter(最简可用)
第一步:在全局头文件(如 format_nested.h)中写入以下代码,不能放在 .cpp 文件里,否则其他源文件调用 std::format 时根本看不到这个特化。
第二步:严格使用全特化语法 template struct std::formatter<:vector>>, char></:vector>,偏特化(比如带 typename T)会被编译器直接忽略。
第三步:parse() 函数必须返回 ctx.begin() 或校验后的位置,绝不可写 return ctx.end();,否则 {:x} 这类非法格式说明符会被静默吞掉,后续可能引发未定义行为。
立即学习“C++免费学习笔记(深入)”;
第四步:format() 中遍历外层 vector,对每个内层 vector 调用 std::format_to(out, "[{}]", inner),注意这里用的是 std::format_to,不是 std::format;内层元素仍用 std::format_to(out, "{}", elem),由内置 formatter 自动处理。
支持任意深度嵌套的 ADL 递归方案
该方法不依赖具体类型名,只要容器满足 begin()/end() 和有 value_type,就能自动递归格式化,比如 std::map<:string std::vector double>>></:string> 也能输出可读结构。
方法一:定义自由函数 format_container,接收迭代器范围和缩进层级参数,内部用 SFINAE 检测 value_type 是否为容器;若是,则递归调用自身并增加缩进;若否,则调用 std::format_to(out, "{}", value)。
方法二:在 std 命名空间外、与目标容器同名的命名空间中(例如对 std::vector 就放 namespace std),提供 std::formatter 全特化,其 format() 成员委托给 format_container。
关键点:所有递归调用都必须复用同一个输出迭代器 ctx.out(),禁止构造临时字符串或调用 std::format,否则模板实例化链会爆炸。
绕过标准限制:用 fmt 库开箱即用
如果你不需要死磕标准库,这条路径最快——fmt::format("{}", nested) 对任意深度嵌套容器(包括 std::vector<:map std::vector>>></:map>)都能直接输出带缩进、括号配对、逗号分隔的美化结果。
第一步:添加头文件 #include <fmt/ranges.h>,确保 CMake 或构建系统已链接 fmt 库(如 find_package(fmt REQUIRED))。
第二步:直接调用 fmt::format("{}", v),无需任何特化代码;若需自定义外层括号,可写 fmt::format("[{}]", v)。
注意:fmt::print 和 fmt::format 都原生支持 std::tuple 和结构化绑定,这点 std::format 完全做不到。
封装独立递归函数避免模板污染
当你想完全避开 std::formatter 特化、又不愿引入第三方库时,可封装一个纯函数式工具,它不修改任何命名空间,只靠 std::format_to 向指定输出器写入。
① 定义模板函数 recursive_format_to,用 requires 约束仅对容器类型启用(检测 begin()、end()、value_type)。
② 对非容器类型,直接调用 std::format_to(out, "{}", value);对容器类型,先写 '[',再用 range-for 遍历,每个元素前加 ", "(首元素除外),递归调用自身,最后写 ']'。
③ 在业务代码中调用:std::string s; recursive_format_to(std::back_inserter(s), v);——这行执行完,s 就是美化后的字符串。


















