【C++ 格式化输出 】C++20 现代C++格式化:拥抱std--format简化你的代码

1. 引言

在本文中,我们将详细讨论C++格式化的传统问题与挑战,以及C++20标准中引入std::format的背景。

传统C++格式化的问题与挑战

传统C++格式化存在一些问题与挑战,主要包括以下几点:

  1. 可读性差:使用C++中的printfscanf家族函数进行格式化输出和输入时,它们的语法较为复杂,难以阅读。在较大的代码项目中,可读性差会导致维护困难。
  2. 类型安全性差printfscanf等函数无法在编译期间检查参数的类型是否正确。这可能导致运行时错误,甚至引发程序崩溃。
  3. 不够灵活:对于复杂的格式化需求,printfscanf等函数提供的功能有限。例如,它们不支持自定义类型的格式化,也不方便处理宽字符和多字节字符集。
  4. 性能开销:由于传统的格式化方法在运行时需要处理格式字符串,它们可能导致额外的性能开销。

C++20引入std::format的背景

鉴于传统C++格式化方法的局限性,C++20标准中引入了std::format库,旨在提供一种更现代、更安全、更灵活的格式化方法。引入std::format的主要动机包括:

  1. 提高可读性std::format采用了一种更加简洁、易懂的语法,使得格式化字符串更具可读性。
  2. 增强类型安全std::format在编译期间就可以检查参数类型的正确性,从而降低运行时错误的风险。
  3. 扩展功能std::format支持自定义类型的格式化,同时兼容宽字符和多字节字符集。这使得开发人员能够满足更为复杂的格式化需求。
  4. 性能优化std::format设计时充分考虑了性能问题,相比传统的格式化方法,它在许多场景下能够提供更高的性能。

总之,std::format作为C++20标准的一部分,旨在解决传统C++格式化方法的问题,并为开发者提供一种更现代、更安全、更灵活的格式化工具。

2. std::format简介

在本节中,我们将简要介绍std::format的基本概念,并对比std::formatprintfiostreams之间的差异。

std::format的基本概念

std::format是C++20标准库中新增的一个格式化工具,它基于Python中的str.format()函数,提供了一种类型安全且易于阅读的字符串格式化方法。std::format的主要特点包括:

  1. 替换字段std::format使用花括号{}作为替换字段的占位符。这些替换字段在格式化时会被相应的参数值替换。
  2. 格式规范std::format支持在替换字段内部定义格式规范,例如指定输出宽度、对齐方式和填充字符等。格式规范使用冒号:分隔,放在花括号内。
  3. 编译时类型检查std::format在编译期间检查参数类型的正确性,以提高类型安全性。
  4. 自定义类型支持std::format可以通过重载formatter特化来支持自定义类型的格式化。

std::format与printf、iostreams的对比

下面我们将对比std::formatprintfiostreams之间的主要差异:

  1. 可读性std::format使用花括号作为占位符,并允许在占位符内定义格式规范。这使得格式化字符串更具可读性,相较于printfiostreams更为简洁明了。

    示例:

    std::cout << std::format("Hello, {}!\n", "World"); // std::format
    printf("Hello, %s!\n", "World");                  // printf
    std::cout << "Hello, " << "World" << "!\n";       // iostreams
    
    
  2. 类型安全std::format在编译期间检查参数类型的正确性,而printf在运行时检查类型。iostreams也具有类型安全性,但std::format更接近printf的语法,使得从printf迁移到std::format更容易。

  3. 扩展性std::format支持自定义类型的格式化,而printf仅支持内置类型。iostreams通过重载插入和提取操作符支持自定义类型,但std::format提供更为统一的扩展方法。

  4. 性能std::format在设计时充分考虑了性能问题,因此在许多场景下性能优于iostreams。而与printf相比,std::format的性能表现也非常出色。

综上所述,std::format在可读性、类型安全性、扩展性和性能方面都表现优异,成为现代C++编程中推荐的字符串格式化工具。

高效使用std::format的理由

以下是为什么应该高效使用std::format的几个理由:

  1. 统一的格式化语法std::format提供了一种统一的格式化语法,无论是内置类型还是自定义类型,都可以使用相同的方法进行格式化。这有助于简化代码并降低维护成本。
  2. 简化代码:由于std::format提供了更简洁的语法,使用它可以减少代码量,使代码更易于理解。相较于printfiostreamsstd::format更适合处理复杂的字符串格式化需求。
  3. 避免运行时错误std::format在编译期间检查参数类型,能够减少因类型错误导致的运行时错误。这有助于提高代码的健壮性和稳定性。
  4. 易于迁移:对于已经习惯使用printf的开发者,std::format提供了类似的语法和功能,可以轻松从printf迁移到std::format
  5. 便于调试和优化std::format的性能表现优异,且支持各种格式化选项,方便开发者进行调试和性能优化。

总之,std::format作为C++20标准库的一部分,为开发者提供了强大、易用的字符串格式化工具。使用std::format可以简化代码、提高可读性、增强类型安全性,并有助于提高代码的健壮性和性能。因此,在现代C++编程中,高效使用std::format是非常重要的。

3. 基本用法

在本节中,我们将介绍std::format的基本用法,包括格式字符串与占位符、类型规格与格式选项的使用。

格式字符串与占位符

std::format使用格式字符串来定义输出的格式。格式字符串中的占位符用花括号{}表示,可以包含以下几个部分:

  • 参数索引:位于花括号内的数字,用于指定要替换的参数的位置。例如,{0}表示第一个参数,{1}表示第二个参数,依此类推。
  • 格式规范:位于冒号:之后的部分,用于指定参数的格式选项。例如,{:d}表示将参数格式化为十进制整数。
  • 文本:花括号之间可以包含任意文本,这些文本将原样输出。例如,{0} is {1}中的is会原样输出。

以下是一些基本的例子:

#include <iostream>
#include <format>

int main() {
    int age = 30;
    double pi = 3.1415926;
    std::string name = "Alice";

    std::cout << std::format("My name is {0} and I am {1} years old.\n", name, age);
    std::cout << std::format("Pi is approximately {0}.\n", pi);

    return 0;
}

类型规格与格式选项

std::format支持各种类型规格与格式选项,以便对输出进行详细的控制。以下是一些常见的类型规格与格式选项:

  1. 整数

    • d:十进制整数。
    • x:小写十六进制整数。
    • X:大写十六进制整数。
    • o:八进制整数。
    • b:二进制整数。
      示例:
    std::cout << std::format("{0:d} {0:x} {0:X} {0:o} {0:b}\n", 42);
    
    
  2. 浮点数

    • f:固定点表示法。
    • e:小写科学计数法。
    • E:大写科学计数法。
    • g:根据值选择最简表示法(fe)。
    • G:根据值选择最简表示法(fE)。
      示例:
    std::cout << std::format("{0:f} {0:e} {0:E} {0:g} {0:G}\n", 3.1415926535);
    
    
  3. 字符串

    • s:字符串。
      示例:
    std::cout << std::format("{:s}\n", "Hello, World!");
    
    
  4. 宽度、对齐和填充

    • <:左对齐。
    • >:右对齐。
    • ^:居中对齐。
    • 数字:指定输出宽度。
    • 字符:指定填充字符。
      示例:
    std::cout << std::format("{:<10} | {:>10} | {:^10}\n", "left", "right", "center");
    std::cout << std::format("{:*<10} | {:#>10} | {:_^10}\n", "left", "right", "center");
    
    
  5. 精度

    对于浮点数,精度用于指定小数点后的位数;对于字符串,精度用于指定最大输出长度。

    示例:

    std::cout << std::format("{:.2f} | {:.3e} | {:.4s}\n", 3.1415926, 12345.6789, "abcdefgh");
    
  6. 整数和浮点数的进位

    整数和浮点数的进位可以使用#选项,它会在八进制和十六进制数字前添加00x0X)前缀,或在浮点数上强制输出小数点。

    示例:

    std::cout << std::format("{:#x} | {:#o} | {:#f}\n", 42, 42, 3.14);
    
    
  7. 正负号

    使用+选项可以强制输出正数的正号。

    示例:

    std::cout << std::format("{:+d} | {:+f}\n", 42, 3.14);
    
    
  8. 自定义类型

    : 要格式化自定义类型,需要为类型特化std::formatter模板,并提供parseformat成员函数。这使得std::format可以以一种统一的方式处理内置类型和自定义类型。

    示例:

    struct Point {
        int x, y;
    };
    
    template<>
    struct std::formatter<Point> {
        auto parse(format_parse_context& ctx) {
            return ctx.begin();
        }
    
        auto format(const Point& p, format_context& ctx) {
            return std::format_to(ctx.out(), "({:d}, {:d})", p.x, p.y);
        }
    };
    
    std::cout << std::format("{0}\n", Point{3, 4});
    
    

4. 格式化数字

在使用std::format时,您可能会需要更多地控制数字的格式。在本节中,我们将详细讨论数字格式化的选项,包括宽度、精度、填充、正负号显示、进制转换以及浮点数格式化选项。

控制数字的宽度、精度与填充

要控制数字的宽度,请在格式说明符中指定一个整数。此外,您还可以使用0指定填充字符,例如{:05}表示将数字格式化为至少5个字符宽,不足部分用零填充。以下是一些示例:

std::cout << std::format("{:5}", 42); // "   42"
std::cout << std::format("{:05}", 42); // "00042"

对于浮点数,您可以使用.后接一个整数来指定精度。例如:

std::cout << std::format("{:.2f}", 3.14159); // "3.14"

显示或隐藏正负号

要显示数字的正负号,可以使用+标志。例如:

std::cout << std::format("{:+}", 42); // "+42"
std::cout << std::format("{:+}", -42); // "-42"

进制转换(十进制、十六进制、八进制等)

要将数字格式化为其他进制,可以使用以下格式说明符:

  • d:十进制(默认)
  • x:十六进制(小写字母)
  • X:十六进制(大写字母)
  • o:八进制
  • b:二进制(小写字母)
  • B:二进制(大写字母)

以下是一些示例:

std::cout << std::format("{:x}", 42); // "2a"
std::cout << std::format("{:X}", 42); // "2A"
std::cout << std::format("{:o}", 42); // "52"
std::cout << std::format("{:b}", 42); // "101010"

浮点数格式化选项

对于浮点数,您可以使用以下格式说明符:

  • f:定点表示(默认)
  • F:定点表示(无穷大和非数字为大写表示)
  • e:科学计数法(小写字母)
  • E:科学计数法(大写字母)
  • g:通用格式,根据值的大小和指定精度自动选择定点表示或科学计数法(小写字母)
  • G:通用格式,根据值的大小和指定精度自动选择定点表示或科学计数法(大写字母)

以下是一些示例:

std::cout << std::format("{:.2F}", 42.123); // "42.12"
std::cout << std::format("{:.2e}", 42.123); // "4.21e+01"
std::cout << std::format("{:.2E}", 42.123); // "4.21E+01"
std::cout << std::format("{:.2g}", 42.123); // "42.12"
std::cout << std::format("{:.2G}", 42.123); // "42.12"
std::cout << std::format("{:.2g}", 0.000421); // "0.000421"
std::cout << std::format("{:.2G}", 0.000421); // "0.000421"


通过上述示例,您可以看到不同浮点数格式化选项的使用方法。这使得std::format成为一个非常灵活和强大的工具,能够处理各种数字格式化需求。请尝试根据您的应用需求进行调整和组合这些选项。

5. 格式化文本

在使用std::format时,除了处理数字之外,您还需要考虑如何格式化文本。本节将讨论如何使用std::format来处理字符串的宽度、填充、特殊字符、转义以及多语言和Unicode字符。

控制字符串的宽度与填充

要设置字符串的最小宽度,请在格式说明符中指定一个整数。您还可以通过在整数前加上填充字符来设置填充字符。以下是一些示例:

std::cout << std::format("{:10}", "hello"); // "hello     "
std::cout << std::format("{:_<10}", "hello"); // "hello_____"

处理特殊字符与转义

要在格式化字符串中包含大括号{},请使用两个连续的大括号{{}}进行转义。以下是一个示例:

std::cout << std::format("The set contains {{1, 2, 3}}"); // "The set contains {1, 2, 3}"

要在格式化字符串中包含反斜杠和其他特殊字符,请使用反斜杠进行转义,如\n表示换行符,\t表示制表符等。例如:

std::cout << std::format("Line 1\\nLine 2"); // "Line 1\nLine 2"

使用std::format处理多语言与Unicode

std::format支持Unicode字符和多语言文本处理。为了确保正确处理Unicode字符,请使用u8前缀表示UTF-8编码的字符串字面值。以下是一个示例:

std::cout << std::format(u8"你好,世界!"); // "你好,世界!"

在处理Unicode字符串时,确保使用正确的编码,否则可能会导致乱码或无法解释的字符。std::format兼容C++17及更高版本的std::u8string类型,允许您更轻松地处理多语言文本。

总之,std::format提供了处理字符串宽度、填充、特殊字符、转义以及多语言和Unicode字符的能力。这使得std::format成为一个非常适用于现代C++应用程序的强大工具。

6. 格式化日期与时间

std::format可以与C++的chrono库一起使用,方便地格式化日期和时间。本节将讨论如何使用std::format处理时间点、持续时间、时间格式化选项以及本地化日期和时间的显示。

使用chrono库处理时间点与持续时间

chrono库提供了表示时间点和持续时间的类,如system_clock::time_pointsteady_clock::time_pointduration等。要使用std::format格式化这些类型,首先需要包含<chrono><format>头文件。

以下是一个示例:

#include <chrono>
#include <format>
#include <iostream>

int main() {
    auto now = std::chrono::system_clock::now();
    auto seconds_since_epoch = std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch());
    std::cout << std::format("Seconds since epoch: {}\n", seconds_since_epoch.count());
}

时间格式化选项

要格式化日期和时间,可以使用扩展的格式说明符,如下所示:

  • %Y:四位年份
  • %m:月份(01-12)
  • %d:月份中的第几天(01-31)
  • %H:小时(00-23)
  • %M:分钟(00-59)
  • %S:秒(00-60,因闰秒可能为60)

为了使用这些格式化选项,需要先将chrono中的time_point转换为std::tm结构,并包含<iomanip>头文件。以下是一个示例:

#include <chrono>
#include <format>
#include <iomanip>
#include <iostream>

int main() {
    auto now = std::chrono::system_clock::now();
    auto now_t = std::chrono::system_clock::to_time_t(now);
    auto now_tm = *std::localtime(&now_t);

    std::cout << std::format("{:%Y-%m-%d %H:%M:%S}\n", now_tm);
}

本地化日期与时间的显示

要显示本地化的日期和时间,可以使用std::locale。使用imbue()函数将流与特定的语言环境关联起来。以下是一个示例:

#include <chrono>
#include <format>
#include <iomanip>
#include <iostream>
#include <locale>

int main() {
    auto now = std::chrono::system_clock::now();
    auto now_t = std::chrono::system_clock::to_time_t(now);
    auto now_tm = *std::localtime(&now_t);

    std::locale::global(std::locale(""));
    std::cout.imbue(std::locale());

    std::cout << std::format("{:%c}\n", now_tm);
}

请注意,std::locale::global()imbue()函数的参数取决于您的平台和语言设置。本示例设置为系统默认语言环境。您还可以为特定的流或字符串指定语言环境。

通过以上方法,您可以使用std::format来灵活地处理和格式化日期与时间。与C++的chrono库结合使用,可以更方便地处理时间点和持续时间,同时允许您定制时间格式化选项以适应不同的应用场景。同时,通过std::locale类,您还可以实现日期和时间的本地化显示,以适应不同地区的用户。

下面是一些日期和时间格式化选项的示例:

#include <chrono>
#include <format>
#include <iomanip>
#include <iostream>
#include <locale>

int main() {
    auto now = std::chrono::system_clock::now();
    auto now_t = std::chrono::system_clock::to_time_t(now);
    auto now_tm = *std::localtime(&now_t);

    std::cout << std::format("{:%A, %B %d, %Y}\n", now_tm); // 显示星期、月份、日期和年份,例如:"Sunday, April 09, 2023"

    std::cout << std::format("{:%D}\n", now_tm); // 以MM/DD/YY格式显示日期,例如:"04/09/23"

    std::cout << std::format("{:%T}\n", now_tm); // 以HH:MM:SS格式显示时间,例如:"17:30:59"

    std::cout << std::format("{:%r}\n", now_tm); // 以12小时制显示时间,例如:"05:30:59 PM"
}

7. 自定义类型的格式化

std::format允许您为自定义类型实现格式化支持,这为您的自定义类型提供了更好的输出显示。要实现自定义类型的格式化支持,您需要特化std::formatter。在本节中,我们将讨论如何为自定义类型实现格式化输出。

实现自定义类型的格式化支持

要为自定义类型实现格式化支持,您需要为其特化std::formatter,并重载parse()format()成员函数。

以下是实现自定义类型格式化输出的步骤:

  1. 包含<format>头文件。
  2. 为您的自定义类型特化std::formatter
  3. 在特化的std::formatter中,重载parse()format()成员函数。

使用fmt::formatter特化

以下是一个简单的自定义类型(Person)和std::formatter特化的示例:

#include <format>
#include <iostream>
#include <string>

struct Person {
    std::string name;
    int age;
};

template <>
struct std::formatter<Person> {
    constexpr auto parse(format_parse_context& ctx) {
        auto it = ctx.begin();
        auto end = ctx.end();
        if (it != end && *it != '}')
            throw format_error("Invalid format");
        return it;
    }

    auto format(const Person& p, format_context& ctx) {
        return format_to(ctx.out(), "{} ({})", p.name, p.age);
    }
};

示例:为自定义类型实现格式化输出

现在我们已经为Person类型实现了std::formatter特化,可以使用std::format函数轻松格式化Person对象了:

int main() {
    Person alice{"Alice", 30};
    std::cout << std::format("{}", alice) << std::endl; // 输出:"Alice (30)"
}

通过实现std::formatter特化并重载parse()format()成员函数,您可以为自定义类型提供灵活且易于使用的格式化支持。这可以大大提高您的C++代码的可读性和维护性。

8. std::format的高级技巧与应用

在本节中,我们将讨论std::format的一些高级技巧和应用,包括动态生成格式字符串、与其他标准库组件(如容器、文件操作等)的结合使用以及提高格式化性能的建议。

格式字符串的动态生成

在某些情况下,您可能需要根据运行时参数动态生成格式字符串。可以使用std::string或其他字符串处理方法来实现这一点。例如,您可能需要根据用户输入设置小数点后的位数:

#include <format>
#include <iostream>

int main() {
    double pi = 3.141592653589793;
    int precision = 2;
    std::string format_str = "{:." + std::to_string(precision) + "f}";
    std::cout << std::format(format_str, pi) << std::endl; // 输出:"3.14"
}

使用std::format与其他标准库组件(如容器、文件操作等)

std::format可以与其他标准库组件(如容器、文件操作等)一起使用,以提供更高级的格式化功能。以下是一些示例:

  • 与容器一起使用:
#include <format>
#include <iostream>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};
    std::string result = std::format("Numbers: [");
    for (const auto& num : numbers) {
        result += std::format("{}, ", num);
    }
    result = result.substr(0, result.size() - 2) + "]";
    std::cout << result << std::endl; // 输出:"Numbers: [1, 2, 3, 4, 5]"
}

  • 文件操作一起使用:
#include <format>
#include <fstream>
#include <iostream>

int main() {
    std::ofstream output_file("output.txt");
    output_file << std::format("{:<10} {:>10}\n", "Name", "Score");
    output_file << std::format("{:<10} {:>10}\n", "Alice", 95);
    output_file << std::format("{:<10} {:>10}\n", "Bob", 80);
    output_file.close();
    std::cout << "Output saved to output.txt" << std::endl;
}

提高格式化性能的建议

虽然std::format在很多方面都比传统的格式化方法更高效,但在某些情况下,性能仍然是一个值得关注的问题。以下是一些建议,可以帮助您提高格式化性能:

  1. 避免频繁构建和销毁格式化字符串:在循环或高频调用的函数中避免重复构建格式化字符串。考虑将格式化字符串预先计算并存储为常量或静态变量。
  2. 减少不必要的字符串连接:在可能的情况下,尽量避免使用+运算符连接字符串。可以使用std::format直接构建最终字符串,而不是分段拼接。例如,可以将多个std::format`调用替换为一个带有多个占位符的调用。
  3. 使用预分配的内存:为频繁使用的字符串分配足够的预先分配的内存,以减少内存分配和重新分配的开销。例如,您可以使用std::string::reserve()函数为字符串预留足够的空间。
  4. 避免不必要的类型转换:在可能的情况下,尽量避免在格式化之前将数据类型转换为其他类型。例如,不要在格式化之前将int转换为std::string,而是直接使用int类型的格式规范。
  5. 选择合适的容器和算法:根据具体应用场景选择合适的容器和算法,以实现最佳性能。例如,对于需要快速插入和删除元素的场景,使用std::liststd::deque而不是std::vector

通过遵循以上建议,您可以确保在使用std::format进行格式化操作时实现最佳性能。这将有助于提高您的C++应用程序的整体性能和响应速度。

9. 结论与展望

std::format在现代C++中的地位与作用

std::format是C++20中引入的一个重要特性,它在现代C++中扮演着重要的角色。与传统的C++格式化方法相比,如printfiostreamsstd::format提供了更为强大、灵活和安全的格式化功能。它支持类型安全,易于扩展,支持自定义类型和多语言环境。std::format有助于提高代码的可读性和维护性,使得C++在格式化方面与其他现代编程语言保持同步。

与其他语言的格式化库的比较

std::format的设计受到了其他编程语言中格式化库的启发,如Python的str.format()f-string,以及Rust的std::fmt。与这些库相比,std::format具有类似的功能和语法,同时充分利用了C++的类型系统和编译时特性,以实现最佳性能。

C++标准化进程中格式化相关的未来发展

C++标准化进程将继续发展和完善格式化功能。例如,C++23中可能会引入std::format的扩展,以提供更丰富的格式选项和本地化支持。此外,C++社区也将继续关注其他语言的发展,以确保C++在格式化方面与时俱进。

总之,std::format为C++开发者提供了一种强大且易于使用的格式化工具。它不仅带来了更好的类型安全和扩展性,还为未来的C++标准提供了一个坚实的基础。作为现代C++的一部分,std::format将继续发展和完善,为C++程序员提供更高效和灵活的格式化解决方案。

10.一百个std::format使用示例

#include <iostream>
#include <format>

int main() {
    int num = 42;
    double pi = 3.1415926535;
    std::string str = "Hello, World!";
    std::string long_str = "This is a very long string to showcase precision";

    std::cout << std::format("1. {:d}\n", num);                                   // 1. 整数十进制
    std::cout << std::format("2. {:x}\n", num);                                   // 2. 整数小写十六进制
    std::cout << std::format("3. {:X}\n", num);                                   // 3. 整数大写十六进制
    std::cout << std::format("4. {:o}\n", num);                                   // 4. 整数八进制
    std::cout << std::format("5. {:b}\n", num);                                   // 5. 整数二进制
    std::cout << std::format("6. {:f}\n", pi);                                    // 6. 浮点数固定点表示
    std::cout << std::format("7. {:e}\n", pi);                                    // 7. 浮点数小写科学计数法
    std::cout << std::format("8. {:E}\n", pi);                                    // 8. 浮点数大写科学计数法
    std::cout << std::format("9. {:g}\n", pi);                                    // 9. 浮点数简化小写表示法
    std::cout << std::format("10. {:G}\n", pi);                                   // 10. 浮点数简化大写表示法
    std::cout << std::format("11. {:s}\n", str);                                  // 11. 字符串
    std::cout << std::format("12. {:<10}\n", str);                                // 12. 左对齐
    std::cout << std::format("13. {:>10}\n", str);                                // 13. 右对齐
    std::cout << std::format("14. {:^10}\n", str);                                // 14. 居中对齐
    std::cout << std::format("15. {:*>10}\n", str);                               // 15. 指定填充字符
    std::cout << std::format("16. {:.5s}\n", long_str);                           // 16. 字符串精度
    std::cout << std::format("17. {:.2f}\n", pi);                                 // 17. 浮点数精度
    std::cout << std::format("18. {:#x}\n", num);                                 // 18. 整数进制前缀
    std::cout << std::format("19. {:#o}\n", num);                                 // 19. 整数八进制前缀
    std::cout << std::format("20. {:#f}\n", pi);                                  // 20. 浮点数强制输出小数点
    std::cout << std::format("21. {:d}\n", -num);                                 // 21. 负数整数
    std::cout << std::format("22. {:f}\n", -pi);                                  // 22. 负数浮点数
    std::cout << std::format("23. {:g}\n", 1e-10);                                // 23. 浮点数简化表示法对于极小值的处理
    std::cout << std::format("24. {:G}\n", 1e+10);                                // 24. 浮点数简化大写表示法对于极大值的处理
    std::cout << std::format("25. {:%}\n", 0.5);                                  // 25. 百分数表示
    std::cout << std::format("26. {:%}\n", 0.99);                                 // 26. 百分数表示
    std::cout << std::format("27. {:%}\n", -0.5);                                 // 27. 负数百分数表示
    std::cout << std::format("28. {:L}\n", true);                                 // 28. 布尔值为true时显示字母L
    std::cout << std::format("29. {:P}\n", false);                                // 29. 布尔值为false时显示字母P
    std::cout << std::format("30. {0:*<10} {1:#>10} {2:_^10}\n", "left", "right", "center"); // 30. 多个参数填充、对齐
    std::cout << std::format("31. {:+d}\n", num);                                 // 31. 强制输出正数的正号
    std::cout << std::format("32. {:+f}\n", pi);                                  // 32. 强制输出正数的正号
    std::cout << std::format("33. {:-d}\n", num);                                 // 33. 显示正数时省略正号
    std::cout << std::format("34. {: d}\n", num);                                 // 34. 为正数留出空格
    std::cout << std::format("35. {:10.2f}\n", pi);                               // 35. 指定宽度和精度
    std::cout << std::format("36. {0:d} - {1:s}\n", num, str);                    // 36. 指定参数位置
    std::cout << std::format("37. {:10.2e}\n", 12345.6789);                       // 37. 科学计数法指定宽度和精度
    std::cout << std::format("38. {:05d}\n", num);                                // 38. 整数补零
    std::cout << std::format("39. {:010.2f}\n", pi);                              // 39. 浮点数补零
    std::cout << std::format("40. {:+010.2f}\n", pi);                             // 40. 浮点数补零并强制输出正号
    std::cout << std::format("41. {0:*<10} {1:#>10}\n", str, num);                // 41. 分别指定左填充和右填充
    std::cout << std::format("42. {0:.>{1}}\n", str, 15);                         // 42. 动态指定宽度
    std::cout << std::format("43. {0:^{1}}\n", str, 20);                          // 43. 动态指定居中对齐的宽度
    std::cout << std::format("44. {0:*>{1}.>{2}}\n", long_str, 20, 10);           // 44. 动态指定宽度、精度和填充字符
    std::cout << std::format("45. {:n}\n", 1000000);                              // 45. 使用本地化的千位分隔符
    std::cout << std::format("46. {:04X}\n", num);                                // 46. 大写十六进制补零
    std::cout << std::format("47. {:c}\n", 65);                                   // 47. 将整数解释为ASCII字符
    std::cout << std::format("48. {:010,d}\n", 1000000);                          // 48. 整数千位分隔符和补零
    std::cout << std::format("49. {:20,}\n", 1234567890);                         // 49. 整数千位分隔符和宽度
    std::cout << std::format("50. {0:%}{1:->10}\n", 0.5, "right");                // 50. 百分数表示与右对齐结合
    std::cout << std::format("51. {0:x}{1:10.2f}\n", num, pi);                    // 51. 同一行输出十六进制整数和浮点数
    std::cout << std::format("52. {0:<10}{1:>10}\n", str, num);                   // 52. 左对齐字符串和右对齐数字
    std::cout << std::format("53. {0:*^20s}\n", str);                             // 53. 居中字符串并指定填充字符
    std::cout << std::format("54. {:{},.{}f}\n", 1234567.89, 15, 2);              // 54. 动态指定宽度、精度和千位分隔符
    std::cout << std::format("55. {:A}\n", 0x1.921fb54442d18p+1);                 // 55. 十六进制浮点数大写表示
    std::cout << std::format("56. {:a}\n", 0x1.921fb54442d18p+1);                 // 56. 十六进制浮点数小写表示
    std::cout << std::format("57. {:%.2%}\n", 0.123456);                          // 57. 百分数表示并指定精度
    std::cout << std::format("58. {:0>10}\n", num);                               // 58. 数字补零并右对齐
    std::cout << std::format("59. {:0>10}\n", str);                               // 59. 字符串补零并右对齐
    std::cout << std::format("60. {0:#010x} {1:.{}f}\n", num, pi, 3);             // 60. 整数进制前缀、浮点数动态精度
    std::cout << std::format("61. {0:0{1}X}\n", num, 6);                          // 61. 动态指定整数十六进制大写表示的宽度
    std::cout << std::format("62. {0:0{1}x}\n", num, 8);                          // 62. 动态指定整数十六进制小写表示的宽度
    std::cout << std::format("63. {0:0{1}d}\n", num, 10);                         // 63. 动态指定整数十进制表示的宽度
    std::cout << std::format("64. {0:0{1}o}\n", num, 8);                          // 64. 动态指定整数八进制表示的宽度
    std::cout << std::format("66. {:0{width}.{}f}\n", pi, 3, width = 10);         // 66. 动态指定浮点数的宽度和精度
    std::cout << std::format("67. {:{fill}>{width}}\n", str, fill='-', width=15); // 67. 动态指定字符串右对齐的宽度和填充字符
    std::cout << std::format("68. {0:{fill}<{width}}\n", str, fill='-', width=15);// 68. 动态指定字符串左对齐的宽度和填充字符
    std::cout << std::format("69. {0:0{1},}\n", 1234567890, 15);                  // 69. 整数动态指定宽度、千位分隔符
    std::cout << std::format("70. {0:s} {1:x}\n", "String", num);                 // 70. 在同一行输出字符串和小写十六进制整数
    std::cout << std::format("71. {:08b}\n", num);                                // 71. 补零的二进制整数表示
    std::cout << std::format("72. {0:+>10} {1:-^10}\n", str, num);                // 72. 同时使用填充字符和对齐方式
    std::cout << std::format("73. {0:s} {1:+>10}\n", long_str, num);              // 73. 不同类型的参数使用不同对齐方式
    std::cout << std::format("74. {0:.{1}s}\n", long_str, 10);                    // 74. 动态指定字符串截断长度
    std::cout << std::format("75. {0:<{1}s}\n", long_str, 10);                    // 75. 动态指定字符串左对齐的宽度
    std::cout << std::format("76. {0:.>{1},.{}f}\n", 1234567.89, 15, 2);          // 76. 动态指定浮点数宽度、精度和千位分隔符
    std::cout << std::format("77. {0:.^20}\n", long_str);                         // 77. 居中对齐较长的字符串
    std::cout << std::format("78. {0:.>{1}}\n", long_str, 30);                    // 78. 动态指定字符串右对齐的宽度
    std::cout << std::format("79. {0:.<{1}}\n", long_str, 30);                    // 79. 动态指定字符串左对齐的宽度
    std::cout << std::format("80. {0:.{1}e}\n", pi, 5);                           // 80. 动态指定科学计数法的精度
    std::cout << std::format("81. {0:.{1}E}\n", pi, 5);                           // 81. 动态指定科学计数法的精度(大写表示)
    std::cout << std::format("82. {0:{1}{2}{3}}\n", pi, '>', 10, 'f');            // 82. 分别指定对齐、宽度和格式字符
    std::cout << std::format("83. {0:s} {1:+>10.{}f}\n", long_str, pi, 3);        // 83. 字符串与带符号的浮点数动态精度
    std::cout << std::format("84. {:5}\n", 123);                                  // 84. 整数使用最小宽度
    std::cout << std::format("85. {:05}\n", 123);                                 // 85. 整数使用最小宽度和补零
    std::cout << std::format("86. {:5}\n", "123");                                // 86. 字符串使用最小宽度
    std::cout << std::format("87. {:>5}\n", "123");                               // 87. 字符串使用最小宽度和右对齐
    std::cout << std::format("88. {:^5}\n", "123");                               // 88. 字符串使用最小宽度和居中对齐
    std::cout << std::format("89. {:<5}\n", "123");                               // 89. 字符串使用最小宽度和左对齐

    std::cout << std::format("90. {:{}}\n", 123, 5);                              // 90. 动态指定整数的最小宽度
    std::cout << std::format("91. {:{}}\n", "123", 5);                            // 91. 动态指定字符串的最小宽度
    std::cout << std::format("92. {0:s} {1:+0{2}.{}f}\n", long_str, pi, 10, 3);   // 92. 字符串与带符号的浮点数动态宽度、精度
    std::cout << std::format("93. {0:s} {1:+0{2},.{}f}\n", long_str, 1234567.89, 15, 2); // 93. 字符串与符号的浮点数带小数点
    std::cout << std::format("94. {0:#x} {1:#X}\n", num, num);                    // 94. 十六进制表示,带前缀,分别为小写和大写
    std::cout << std::format("95. {0:#o}\n", num);                                // 95. 带前缀的八进制表示
    std::cout << std::format("96. {0:#b} {1:#B}\n", num, num);                    // 96. 带前缀的二进制表示,分别为小写和大写
    std::cout << std::format("97. {0:#0{1}X}\n", num, 6);                         // 97. 带前缀的十六进制表示,指定宽度和补零
    std::cout << std::format("98. {0:#0{1}o}\n", num, 6);                         // 98. 带前缀的八进制表示,指定宽度和补零
    std::cout << std::format("99. {0:#0{1}b}\n", num, 10);                        // 99. 带前缀的二进制表示,指定宽度和补零
    std::cout << std::format("100. {0:s} {1:#0{2}.{}f}\n", long_str, pi, 10, 3);  // 100. 字符串与带前缀的浮点数动态宽度、精度
} 

  • 12
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泡沫o0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值