fmt库提供类型安全、高性能的字符串格式化,支持c++11及以上版本,语法简洁且可扩展,优于传统printf和iostreams,推荐通过CMake集成,适用于现代C++项目。

fmt 是一个现代 C++ 的格式化库,提供比 iostreams 和 printf 更安全、更高效、更简洁的字符串格式化方式。它被设计为类型安全、无缓冲区溢出风险,并且性能接近甚至优于传统方法。从 C++20 开始,其核心思想已被纳入标准库的 std::format,但 fmt 库本身支持更早的 C++ 版本(如 C++11/14/17),并且功能更丰富。
为什么选择 fmt?
相比传统方式,fmt 有明显优势:
- 类型安全:编译时检查格式字符串与参数类型是否匹配(C++20 起支持),避免 printf 因类型不匹配导致崩溃。
- 简洁语法:使用类似 python 的 {} 占位符,清晰易读。
- 高性能:底层优化良好,通常比 iostreams 快很多,接近甚至超过 sprintf。
- 易于集成:头文件为主,编译简单,支持静态或动态链接。
- 扩展性强:支持自定义类型的格式化。
安装与集成
fmt 支持多种集成方式:
- vcpkg:
vcpkg install fmt - conan:
conan install fmt - CMake + FetchContent(推荐用于项目内嵌):
cmake_minimum_required(VERSION 3.14)
project(myapp)
include(FetchContent)
FetchContent_Declare(
fmt
git_REPOSITORY https://github.com/fmtlib/fmt
GIT_TAG 8.1.1
)
FetchContent_MakeAvailable(fmt)
add_executable(main main.cpp)
target_link_libraries(main fmt::fmt)
如果你只用头文件版本,可直接包含 #include <fmt></fmt> 或 #include <fmt></fmt>。
立即学习“C++免费学习笔记(深入)”;
基本用法
最常用的函数是 fmt::format() 和 fmt::print()。
#include
#include
int main() {
// 格式化字符串
std::String s = fmt::format(“Hello, {}!”, “world”);
std::cout
// 直接打印
fmt::print(“The answer is {}.n”, 42); // 输出: The answer is 42.
// 多个参数
fmt::print(“Values: {}, {}, {}n”, 1, 2.5, “text”);
}
格式化选项
fmt 支持丰富的格式规范,语法为 {:[格式]}。
- 指定类型:
{:d}整数,{:f}浮点,{:x}十六进制 - 宽度与填充:
{:8}宽度为8,{:>8}右对齐,{:_ 左对齐并用下划线填充 - 精度:
{:.2f}保留两位小数 - 科学计数法:
{:e}
fmt::print(“{:08x}n”, 255); // 输出: 000000ff
fmt::print(“{:>10}n”, “right”); // 输出: right
fmt::print(“{:.3f}n”, 3.14159); // 输出: 3.142
fmt::print(“{:+f}n”, 3.14); // 输出: +3.140000
命名参数(C++20 起支持)
提升可读性,尤其在复杂字符串中:
fmt::print(“Hello, {name}! You are {age} years old.n”,
fmt::arg(“name”, “Alice”), fmt::arg(“age”, 30));
注意:命名参数需要启用实验性功能或使用较新版本 fmt。
自定义类型格式化
让你的类也能被 fmt 格式化。以一个简单的 Point 类为例:
Struct Point {
double x, y;
};
template
struct fmt::formatter
constexpr auto parse(format_parse_context& ctx) {
return ctx.begin();
}
template
auto format(const Point& p, FormatContext& ctx) {
return fmt::format_to(ctx.out(), “({:.2f}, {:.2f})”, p.x, p.y);
}
};
// 使用
Point p{1.234, 5.678};
fmt::print(“{}n”, p); // 输出: (1.23, 5.68)
与 std::format 的关系
C++20 引入了 std::format,其设计直接受 fmt 启发。如果你使用 C++20 且不需要 fmt 的高级功能,可以直接用标准库。否则,fmt 提供更好的兼容性和更多特性(如格式化容器、时间库增强等)。
基本上就这些。fmt 让 C++ 字符串格式化变得现代、安全又高效,值得在新项目中采用。集成简单,学习成本低,收益明显。不复杂但容易忽略。