fmt
fmt 快速上手:位置参数、精度与一个小型自定义类型
建立最小 C++20 示例,区分字面量与运行期格式错误,再通过 format_as 复用已有表示,而不是重新编写解析器。
你将学会
- 先让一个确定的例子成立
- 明确错误应该出现在哪个阶段
- 先扩展值的表示,再考虑扩展语法
开始前需要
- 理解基础 C++ 值、引用、字符串与构建目标
- 能够区分文档预期与实际测量结果
追踪具体 fmt 行为,在输出、生命周期和验证边界明确的前提下选择集成方式。
先看结论
- 位置字段让消息顺序变化时仍能保持参数含义。
- 字面量格式与运行期格式需要分开的错误测试。
- format_as 复用已有表示,自定义 formatter 则承担更大的契约。
先让一个确定的例子成立
用包含 fmt/format.h 的小型 C++20 程序链接固定版本的依赖。下面的示例把第二个参数作为标签,第一个参数格式化为两位小数,预期结果是 value: 1.23。单个明确断言就能检查需要的 API,不必同时引入文件写入、远程输入或无关的日志框架。
替换字段使用花括号,冒号后面是呈现规则。像 {1} 和 {0:.2f} 这样的显式位置字段,适合翻译消息中同一组值的顺序变化。一个格式字符串中不能混用自动数字索引与显式数字索引;字面花括号需要重复书写,整套规则也不能直接按 printf 的转换标记理解。
明确错误应该出现在哪个阶段
在支持 C++20 consteval 检查的配置下,把字符串交给字面量中的十进制整数格式,会产生编译错误。用 fmt::runtime 包装相同格式,则把检查移到运行期间;普通启用异常的配置可以通过 fmt::format_error 报告问题。这应是两个刻意分开的测试,不能把后者说成已经预先验证。
语法还允许通过参数提供动态宽度或精度。参数具有合法整数类型,不代表它满足应用自己的大小限制。入门练习应先使用较小的固定宽度,再加入类型不匹配的反例。如果预期失败的字面量居然编译通过,应先检查编译器版本、语言模式和 FMT_USE_CONSTEVAL 配置。
先扩展值的表示,再考虑扩展语法
如果领域值应完全按照某个已有类型呈现,可以在该类型所属命名空间中定义 format_as。配套夹具把包含整数 7 的小对象映射为整数表示,再检查补零后的 0007。这样复用了库已有的整数格式规则,而不是为一个简单对象重新实现解析器。
需要自行解析格式或控制呈现逻辑时,再考虑 formatter 特化。API 文档建议在可行时通过继承或组合复用现有 formatter。两个互相竞争的扩展机制一起添加并不是捷径;应保持一份清晰契约,并针对所暴露表示测试对齐、宽度和非法输入。
实施步骤
- 1
建立链接固定 fmt 源码的 C++20 目标。
- 2
断言位置与精度示例的完整结果。
- 3
把非法字面量放进单独的预期编译失败测试。
- 4
增加一个小型领域类型转换并检查输出。
可复制示例
#include <fmt/format.h>
#include <cassert>
int main() {
const auto result = fmt::format("{1}: {0:.2f}", 1.234, "value");
assert(result == "value: 1.23");
}常见问题
自动数字索引和显式数字索引可以混用吗?
不可以。一个格式字符串应保持一致的索引方式,固定版本的语法文档说明了对应诊断。
fmt::runtime 是绕过校验的方法吗?
它改变的是校验阶段,并不保证非法格式能够成功,也不说明任意宽度都适合你的应用。
资料来源
- doc/get-started.md来源核查 2026-09-08
- doc/api.md来源核查 2026-09-08
- doc/syntax.md来源核查 2026-09-08
- include/fmt/core.h来源核查 2026-09-08
- include/fmt/format.h来源核查 2026-09-08
- test/format-test.cc来源核查 2026-09-08