C/C++ C++20 格式化库 std::format

说明

文本格式化库提供 printf 函数族的安全且可扩展的替用品。有意使之补充既存的 C++ I/O 流库并复用其基础设施,例如对用户定义类型重载的流插入运算符。

头文件
#include <format>
函数定义
template<class... Args>
std::string format(std::string_view fmt, const Args&... args);

template<class... Args>
std::wstring format(std::wstring_view fmt, const Args&... args);

template<class... Args>
std::string format(const std::locale& loc, std::string_view fmt, const Args&... args);

template<class... Args>
std::wstring format(const std::locale& loc, std::wstring_view fmt, const Args&... args);

按照格式字符串 fmt 格式化 args ,并返回作为 string 的结果。 loc 若存在,则用于本地环境特定的格式化。

参数说明

fmt - 表示格式字符串的字符串视图。

格式字符串由以下内容组成:

  • 通常字符(除了 { 与 } ),它们被不加修改地复制到输出
  • 转义序列 {{ 与 }} ,它们在输出中被分别替换成 { 与 }
  • 替换域

每个替换域拥有下列格式:

  • 引入的 { 字符
  • (可选) arg-id ,一个非负数
  • (可选) 冒号( : )后随格式说明
  • 终止的 } 字符

arg-id 指定用于格式化其值的 args 中的参数的下标;若省略 arg-id ,则按顺序使用参数。格式字符串中的 arg-id 必须全部存在或全部被省略。混合手动和自动指定下标是错误。
格式说明由对应参数特化的 std::formatter 定义。

  • 对于基本类型和标准字符串类型,格式说明为标准格式说明
  • 对于标准日期和时间类型,格式说明为 chrono 格式说明
  • 对于用户定义类型,格式说明由用户定义的 std::formatter 特化决定

args… - 要格式化的参数

loc - 用于本地环境特定格式化的 std::locale

返回值

保有格式化结果的 string 对象。

异常

若 fmt 对于提供的参数不是合法的格式字符串则抛出 std::format_error 。并且会传播任何格式化器所抛的异常。
注意,提供多于格式字符串所要求的参数不是错误:

std::format("{} {}!", "Hello", "world", "something"); // OK :产生 "Hello world!"
填充与对齐

基本格式:

填充与对齐(可选) 符号(可选) #(可选) 0(可选) 宽度(可选) 精度(可选) L(可选) 类型(可选)

填充与对齐 是一个可选的填充字符(可为任何 { 或 } 外的的字符),后随对齐选项 < 、 > 、 ^ 之一。对齐选项的意义如下:

  • < :强制域在可用空间内左对齐。这在使用非整数非浮点显示类型时为默认。
  • > :强制域在可用空间内右对齐。这在使用整数或浮点显示类型时为默认。
  • ^ :强制域在可用空间中央,通过在值的前面插入n/2向下取整个字符,后面插入n/2向上取整个字符,其中 n 是待插入的总字符数。
char c = 120;
auto s0 = std::format("{:6}", 42);    // s0 的值为 "    42"
auto s1 = std::format("{:6}", 'x');   // s1 的值为 "x     "
auto s2 = std::format("{:*<6}", 'x'); // s2 的值为 "x*****"
auto s3 = std::format("{:*>6}", 'x'); // s3 的值为 "*****x"
auto s4 = std::format("{:*^6}", 'x'); // s4 的值为 "**x***"
auto s5 = std::format("{:6d}", c);    // s5 的值为 "   120"
auto s6 = std::format("{:6}", true);  // s6 的值为 "true  "
符号、 # 与 0

符号 选项能为下列之一:

  • + :指示符号应该一同用于非负数和负数。在非负数的输出值前插入 + 号。
  • - :指示符号应该仅用于负数(这是默认行为)。
  • 空格:指示应对非负数使用前导空格,而对负数使用负号。

负零被当作负数。符号 选项应用于浮点无穷大和 NaN 。

double inf = std::numeric_limits<double>::infinity();
double nan = std::numeric_limits<double>::quiet_NaN();
auto s0 = std::format("{0:},{0:+},{0:-},{0: }", 1);   // s0 的值为 "1,+1,1, 1"
auto s1 = std::format("{0:},{0:+},{0:-},{0: }", -1);  // s1 的值为 "-1,-1,-1,-1"
auto s2 = std::format("{0:},{0:+},{0:-},{0: }", inf); // s2 的值为 "inf,+inf,inf, inf"
auto s3 = std::format("{0:},{0:+},{0:-},{0: }", nan); // s3 的值为 "nan,+nan,nan, nan"
formatter - 自定义的类型扩展

formatter 的被启用特化对给定类型定义格式化规则。被启用特化必须满足格式化器 (Formatter) 要求。特别是,它们定义成员函数或函数模板 parse 与 format 。

#include <format>
#include <iostream>
	 
// 类型 T 的包装
template<class T>
struct Box {
    T value;
};
 
// 能用被包装值的格式说明格式化包装 Box<T>
template<class T, class CharT>
struct std::formatter<Box<T>, CharT> : std::formatter<T, CharT> {
    // 从基类继承 parse()
 
    // 通过以被包装值调用基类实现定义 format()
    template<class FormatContext>
    auto format(Box<T> t, FormatContext& fc) {
        return std::formatter<T, CharT>::format(t.value, fc);
    }
};
 
int main() {
    Box<int> v = { 42 };
    std::cout << std::format("{:#x}", v);
}

输出:

0x2a

参考:https://zh.cppreference.com/w/cpp/utility/format

发布了78 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/LU_ZHAO/article/details/104528022