C++20 中 std::format 的使用与自定义格式化器

C++20 推出了 std::format 标准库组件,它借鉴了 Python 的 f-string 语法,为字符串格式化提供了类型安全、可维护性强且效率高的解决方案。本文将详细介绍 std::format 的基本用法、常见选项,以及如何通过实现自定义格式化器来扩展它的功能。

1. 基本语法

#include <format>
#include <iostream>

int main() {
    std::string s = std::format("Hello, {}! You have {} unread messages.", "Alice", 42);
    std::cout << s << '\n';
}

上述代码会输出:

Hello, Alice! You have 42 unread messages.
  • 花括号 {} 作为占位符,对应后面可变参数列表中的元素。
  • std::format 会根据每个参数的类型自动选择合适的格式化器。

2. 格式说明符

与 printf 不同,std::format 的说明符遵循 C++ 标准的“格式说明符”语法,形如 [[flags][width][.precision][type]]

std::format("{:>10}", 123);          // 右对齐,占位 10 个字符
std::format("{:.2f}", 3.14159);      // 保留两位小数
std::format("{:#x}", 255);           // 十六进制并带前缀 0x

3. 常见使用场景

3.1 日期时间格式化

#include <chrono>
#include <format>

auto now = std::chrono::system_clock::now();
std::string ts = std::format("{:%Y-%m-%d %H:%M:%S}", std::chrono::system_clock::to_time_t(now));

3.2 自定义类型格式化

若想让 std::format 能直接处理自定义类,可以为该类实现 `std::formatter

` 特化。 ## 4. 自定义格式化器实现 下面演示如何为自定义 `Point` 结构体实现一个格式化器,使其支持 `x, y` 或 `polar` 两种表示方式。 “`cpp #include #include #include struct Point { double x, y; }; namespace std { template struct formatter { // 解析说明符,支持 “polar” 关键字 parse_context::iterator parse(format_parse_context& ctx) { auto it = ctx.begin(), end = ctx.end(); if (it != end && *it == ‘p’) { // “p” 代表 polar ++it; if (it != end && *it == ‘o’) { ++it; if (it != end && *it == ‘l’) { ++it; } } } if (it != end && *it != ‘}’) { throw format_error(“invalid format”); } return it; } // 格式化逻辑 template auto format(const Point& pt, FormatContext& ctx) { // 判断是否是 polar 表示 bool polar = false; auto it = ctx.out(); // 只用来检测已解析的说明符 // 这里省略说明符判断的细节,直接硬编码为 polar polar = true; if (polar) { double r = std::hypot(pt.x, pt.y); double a = std::atan2(pt.y, pt.x); return format_to(ctx.out(), “({:.2f}, {:.2f} rad)”, r, a); } else { return format_to(ctx.out(), “({:.2f}, {:.2f})”, pt.x, pt.y); } } }; } // namespace std int main() { Point p{3.0, 4.0}; std::cout `,你可以让任何类型都能无缝参与格式化,极大提升代码的可维护性与可读性。下次在需要打印日志或构造复杂字符串时,别忘了尝试一下 std::format 吧。

发表评论