目录
我们承担ROS,FastDDS等通信中间件,C++,cmake等技术的项目开发和专业指导和培训,有10年+相关工作经验,质量有保证,如有需要请私信联系。
三向比较运算符
<=>,用于确定两个值的大小顺序。它可以告诉你一个值是否大于,等于,小于另一个值。它返回枚举类型,定义在<compare>
和std命名空间中。如果操作数是整数类型,则结果是强排序,为以下值:
- strong_ordering::less:第一个操作数小于第二个
- strong_ordering::greater:第一个操作数大于第二个
- strong_ordering::equal:第一个操作数等于第二个
如果操作数是浮点型,结果是一个偏序: - partial_ordering::less:
- partial_ordering::greater
- partial_ordering::equivalent:
- partial_ordering::unordered:
弱排序:
在C++20中,只要重载==
和<==>
,C++20就会自动为所有6个比较运算符(>, ==, <, >=, <=, !=)提供支持。
基于范围for循环的初始化器
与if和switch语句中的用法相似,
for(<initializer>; <for-range-declaration>: <for-range-initializer>) { ... }
<initializer>
只能被用于范围for循环体内
指派初始化器
聚合类型是满足以下要求的数组类型的对象或是结构体或类的对象:仅public数据成员,五用户声明或继承的构造函数,无虚函数和虚基类、private或protected的基类。
指派初始化器使用名称初始化聚合的数据成员,以点开头,后跟数据成员的名称。
指派初始化的顺序必须与数据成员的声明顺序一致,不允许混合使用指派初始化器和非指派初始化器。未使用指派初始化器初始化的任何数据成员都将使用默认值进行初始化。
class MyClass {
public:
int a;
char b;
double c;
};
// 指派初始化
MyClass obj {
.a = 1,
.c = 12.3
};
指派初始化的优点:
- 使用数据成员的默认值的话可以跳出初始化,这在列表初始化中是不允许的
- 当新成员被添加到数据结构时,使用指派初始化器的现有代码将继续起作用,新成员将使用默认值进行初始化。
consteval
constexpr int con_test(int i) {
return i * 2;
}
constexpr int a = 6;
constexpr int b{ con_test(a) }; // 编译期求值
int c = 7;
int d { con_test(c); } // 运行时求值
如果希望保证始终在编译期间对函数进行求值,使用关键字consteval代替constexpr将函数转换为immediate function(立即函数),此时对d的求值就会在编译期间报错。
std::bit_cast
字符串格式化
std::format
头文件定义在#include<format>
中。C++20中引入std::format用来格式化字符串,基本结合了C风格的函数和C++ IO流的所有优点,是一种类型安全且可扩展的机制。
- 格式说明符:
- width
- align
- sign
- 备用格式
- type
- precision
- 格式说明符错误将抛出
std::format_error
的异常 - 支持自定义类型
属性
[[likely]] / [[unlikely]] 用于帮助编译器优化代码,例如这些属性可用于根据某个分支被采用的可能性来标记if和switch语句的分支。不过目前很少需要这些属性,因为编译器和硬件有足够强大的分支预测功能,可以自行解决。
if(value) [[unlikely]] { ... } else { ... }
switch(value) {
[[likely]] case 1: ...
break;
[[unlikely]] case 2: ...
...
explict
可以将布尔值传给explicit,以将其转换为条件explicit。语法如下:
explicit(true) MyClass(int)
- 这个特性在使用类型萃取的泛型模板代码中非常有用
模块
头文件的问题:
- 避免多次包含
- 头文件包含的顺序问题
- #include的包含就会增加数万行编译器要处理的代码
C++20引用模块解决了这类问题:
- 模块导入的顺序不重要
- 模块只需要编译一次,而不是像头文件那样需要多次编译
- 模块中的某些修改(如在模块接口文件中修改一个导出函数的实现)不会触发该模块的用户重新编译
- 模块不受外部定义的宏的影响,并且在模块内部定义的任何宏对模块外部的任何代码都不可见
模块接口文件
模块接口文件是为模块提供的功能定义的接口。模块接口文件linux上以.cppm,vs上以.ixx作为扩展名(还没有标准化的扩展名)。
模块接口以声明开头,声明该文件正在定义一个具有特定名称的模块。
模块需要显式声明要导出的内容,即当用户代码导入模块时,哪些内容应该是可见的。使用export关键字从模块中导出实体。任何没有从模块中导出的内容只在改模块中可见。
使用关键字import导入模块
- 函数的定义如果直接放在类定义中,默认是inline,但在模块导出的类中不再如此,如果希望这些方法是内联的,需要显式用inline指定
特性测试宏
- __cpp_range_based_for
- __cpp_binary_literals
- __cpp_char8_t
- __cpp_generic_lambdas
- __cpp_consteval
- __cpp_coroutines
- __has_cpp_attribute(fallthrough)
source_location
C++20之前可以通过__FILE__
和__LINE__
等获取源码的位置信息,C++20中使用std::source_location
(#include<source_location>
)代替C风格的预处理宏。
公有方法:
file_name()
:包含当前源代码文件名function_name()
:如果当前位置在函数中,则包含当前函数名line()
:包含当前源代码中的行号column()
:包含当前源代码中的当前列号
静态方法 current()
:可以在方法被调用的源代码位置上创建source_location实例
其他特性
- string方法新增starts_with(str)和ends_with(str):字符串以给定的字串开始或结尾则返回true,否则false
- 从C++20开始string是一个constexpr类,这意味着string可用于在编译器执行操作,并可用于constexpr函数和类的实现