C++20 STL CookBook读书笔记1

目录

关于std::print

定义自己格式的打印符


关于std::print

现在是2024年,大部分的编译器已经支持了std::print函数。对于MSVC环境那就是打开C++23标准(因为还没有非常全面的支持,可能现在你需要打开的是latest,几年后的读者看到这篇博客可能就会使专门的23标准了!)。Cookbook的实现也就变得没有必要。

我们现在就可以试试一些常见的用法。

复制代码
#include <print>
​
static constexpr const char* name = "Charlie";
static constexpr const double pi = 3.14159265358979323846;
static constexpr const int age = 25;
​
int main() {
    std::println("Hello, world!");
    std::println("Hello, {}!", name);
    std::println("The value of pi is {:.2f}.", pi);
    std::println("My name is {1} and I am {0} years old.", age, name);
    std::println("what the hell of this :O: {:.^10}", age);
    return 0;
}
​

很好!这就是一个简单的std::println的demo程序。实际上,关于format的格式,我列在下面

格式说明符 描述 示例
{} 默认格式 std::format("{}{}", "Hello", "World") 输出 HelloWorld
{:d} 整数格式 std::format("{:d}", 42) 输出 42
{:x} 十六进制格式 std::format("{:x}", 255) 输出 ff
{:o} 八进制格式 std::format("{:o}", 255) 输出 377
{:b} 二进制格式 std::format("{:b}", 255) 输出 11111111
{:f} 浮点数格式,默认6位小数 std::format("{:f}", 3.14159) 输出 3.141590
{:e} 科学计数法格式 std::format("{:e}", 1000) 输出 1.000000e+03
{:g} 自动选择浮点数格式,简洁 std::format("{:g}", 0.000123) 输出 0.000123
{:0.2f} 指定小数位数(2位小数) std::format("{:.2f}", 3.14159) 输出 3.14
{:>10} 右对齐,宽度为10 std::format("{:>10}", "test") 输出 test
{: <10} 左对齐,宽度为10 std::format("{:<10}", "test") 输出 test
{:^10} 居中对齐,宽度为10 std::format("{:^10}", "test") 输出 test
{:10} 右对齐,宽度为10,默认填充空格 std::format("{:10}", 42) 输出 42
{:0<10} 左对齐,宽度为10,填充字符为0 std::format("{:0<10}", 42) 输出 4200000000

对照这个表格,我想我们就不难才出来最后一句话的含义了:

复制代码
std::println("what the hell of this :O: {:.^10}", age);

打印10个字符宽度的字符:让我们的age是居中对齐的,其余部分使用.来进行填充。

定义自己格式的打印符

我们还可以定义自己的类的输出方式,办法是老老实实的重载我们的模板类std::formatter的偏特化的类。

以一个我们想要表达的分数的结构体作为示例,我们来试试看:

复制代码
/*
    Time: 2024-10-22 19:59:30
    Author: Charlie
    Description:    This is a demo program to 
                    show how to use self defined formatter
*/
#include <format>
#include <print>
struct Frac {
    int numerator;
    int denominator;
};
​
template<>
struct std::formatter<Frac> {
​
    template<typename ParseContext>
    constexpr ParseContext::iterator parse(ParseContext& ctx) {
        return ctx.begin();
    }
​
    template<typename FormatContext>
    FormatContext::iterator format(const Frac& frac, FormatContext& ctx) const {
        return std::format_to(ctx.out(), "{}/{}", frac.numerator, frac.denominator);
    }
​
};
​
int main() {
    Frac f{3, 4};
    std::print("The fraction is {}\n", f);
    return 0;
}

请注意!务必保证函数的签名完全对的上,否则SAFNAE了给你炸一个static_assert failed连问题出在什么地方都不知道。

好,看完了,我来说说每一个函数都在做什么:

  • parse() 函数解析冒号之后(如果没有冒号,则解析左括号之后)到右括号(但不包括)的格式字符串。(换句话说,指定对象类型的部分。)它接受一个 ParseContext 对象并返回一个迭代器。就我们的目的而言,我们可以只返回 begin() 迭代器,因为我们的类型不需要任何新语法。您很少需要在这里放置任何其他东西。

  • format() 函数接受一个 Frac 对象和一个 FormatContext 对象。 它返回一个结束迭代器。format_to() 函数使这变得简单。它接受一个迭代器、一个格式字符串和一个参数包。在本例中,参数包是我们的 Frac 类的两个属性,即分子和分母。 我们在这里需要做的就是提供一个简单的格式字符串"{}/{}"以及分子和分母值。

相关推荐
Theodore_10222 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
‘’林花谢了春红‘’4 小时前
C++ list (链表)容器
c++·链表·list
----云烟----4 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024064 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic5 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it5 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康5 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神5 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
机器视觉知识推荐、就业指导5 小时前
C++设计模式:建造者模式(Builder) 房屋建造案例
c++
宅小海5 小时前
scala String
大数据·开发语言·scala