std::format 在 GCC 13+、Clang 15+(配 libc++ 15+ 或新版 libstdc++)、MSVC 2019 16.10+(推荐 2022 17.0+)可用,需启用 C++20 且标准库版本匹配;MinGW-w64 当前不推荐。

std::format 在哪些编译器和标准库版本可用
它不是“写了就能跑”的功能——std::format 要求编译器支持 C++20 且标准库实现已完整提供该特性。GCC 13+(需 -std=c++20 且链接 libstdc++ 13.1+)、Clang 15+(配合 libc++ 15+ 或较新 libstdc++)、MSVC 2019 16.10+(预览版起支持,2022 17.0+ 更稳定)。用 Clang 编译时若报错 no member named 'format' in namespace 'std',大概率是没启用 -stdlib=libc++ 或 libc++ 版本太旧。
- Linux 下检查 libstdc++ 版本:
strings /usr/lib/x86_64-linux-gnu/libstdc++.so.6 | grep GLIBCXX,确认含GLIBCXX_3.4.30或更高 - MSVC 用户需在项目属性中启用“C++ Language Standard”为
/std:c++20,并确保平台工具集 ≥ v143 - MinGW-w64 目前仍不推荐用于
std::format,多数发行版未同步实现,容易触发 internal compiler error
基本用法与常见格式说明符
std::format 行为接近 Python 的 str.format(),但语法更贴近 printf 风格的格式说明符(如 {}、{:d}、{:.2f}),不支持位置参数缩写(如 {0} 必须显式写成 {0:d})。
- 整数默认十进制:
std::format("{}", 42)→"42";加#前缀可启用进制标识:std::format("{:#x}", 255)→"0xff" - 浮点数控制精度:
std::format("{:.3f}", 3.14159)→"3.142";{:e}切换科学计数法,{:g}自动选最短表示 - 字符串无需额外修饰:
std::format("Hello, {}!", "World")→"Hello, World!";但若要填充或对齐,得用{:(左对齐宽10)、<code>{:>8}(右对齐宽8) - 注意:空格填充是默认行为,
{:^6}居中,{:*^6}用*替代空格
std::format 与 std::sprintf / fmt::format 的关键差异
它不接受可变参数模板以外的“格式化缓冲区”操作,也不支持运行时拼接格式字符串(即 format string 必须是字面量或 consteval 表达式),否则编译失败。
- ❌ 错误写法:
std::string fmt = "{} + {}"; auto s = std::format(fmt, a, b);→ 报错format string is not a string literal - ✅ 正确替代:
std::format("{} + {}", a, b),或用std::vformat+std::make_format_args支持运行时格式串(但性能略低、代码更冗长) - 相比
fmt::format,std::format不支持自定义类型自动格式化(除非特化std::formatter),也不带fmt::print这类便捷输出函数 - 性能上,
std::format多数场景比sprintf安全但略慢;若频繁调用且格式固定,建议缓存std::format_string(C++23 引入,C++20 中不可用)
如何为自定义类型添加 std::format 支持
必须显式特化 std::formatter 模板,并实现 parse() 和 format() 成员函数。这个过程不自动推导,也不能靠 ADL 查找。
立即学习“C++免费学习笔记(深入)”;
- 特化必须在
std命名空间内,且针对具体类型(如struct Point { int x, y; };)写template struct std::formatter<point></point> -
parse()负责解析格式说明符(如"{:x}"中的x),返回迭代器位置;若忽略格式控制,可直接返回ctx.end() -
format()接收值、格式上下文和 parse 返回的迭代器,调用ctx.out()写入结果,例如:return std::format_to(ctx.out(), "({},{})", p.x, p.y); - 注意:
std::format_to是底层接口,别误用std::format递归调用自己,容易栈溢出
std::format 看似简单,但实际落地时编译器支持碎片化、格式串必须字面量、自定义类型支持门槛高这三点,最容易卡住。尤其在跨平台项目里,别假设所有环境都 ready —— 先查 __cpp_lib_format 宏,再决定是否 fallback 到 fmt 库。


















