C++ 新版本特性 - C++20
DANGER
C++20下面的代码未在环境上编译测试使用,仅用于理论知识补充,后期升级gcc版本再进行实测。
参考资料
特性概览
The Big Four
Concepts
C++中模板编程极大地简化了代码的编写,但同时也会带来一些使用上的疑惑,例如,判断两个数是否相等,C++17提供了concept机制,用来检查模板参数类型:
#include <concepts>
#include <iostream>
template <typename T>
concept Integeral = std::is_integral<T>::value;
template <Integeral T>
auto isEqual(T left, T right) {
return left == right;
}
int main() {
cout << std::boolalpha;
double a = 2.334;
double b = 2.335;
std::cout << isEqual(2, 2) << std::endl; // true
std::cout << isEqual(b - a, 0.001) << std::endl; // false
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Range library
ranges:代表一段元素,之前版本使用begin和end标识一段元素。
ranges优点:
- 简化语法和操作;
- 防止begin,end迭代器的不配对使用;
- 使得类似管道|的串行操作成为可能。
相关概念:
- View:延迟计算,只有读权限
- Actions:即时处理,读或写
- Algorithms:操作range
- Views和Actions的串联操作
#include <concepts>
#include <iostream>
//简化操作:
void simple_action()
{
std::cout << "simple_action" << std::endl;
std::vector<int> vec{3, 1, 2, 5, 6, 4};
// std::sort()
std::sort(vec.begin(), vec.end());
std::copy(vec.begin(), vec.end(), std::ostream_iterator<int>{cout, " "}); // 1 2 3 4 5 6
// ranges::sort()
std::ranges::sort(vec);
std::ranges::copy(vec, std::ostream_iterator<int>{cout, " "}); // 1 2 3 4 5 6
}
//串联视图:
void view_action()
{
std::cout << "view_action" << std::endl;
std::vector<int> vec{1, 2, 3, 4, 5, 6};
auto even = [](int i){ return i % 2 == 0; };
auto square = [](int i){ return i * i; };
auto result = vec | std::views::filter(even) | std::views::transform(square);
/* 此时 result 并没有被计算,只是定义了一系列视图,只有到下面的遍历操作时,result 触发,即所谓延迟计算 */
for (auto i : result)
{
cout << i << " "; // 4 16 36
}
}
//过滤和变换:
void filter_transfrom_action()
{
std::cout << "filter_transfrom_action" << std::endl;
std::vector vec{1, 2, 3, 4, 5};
auto result = vec | std::views::transform([](int i){ return i * i; }) | std::views::take(3);
cout << std::accumulate(result.begin(), result.end(), 0) << endl; // 14
}
int main()
{
simple_action();
view_action();
filter_transfrom_action();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
Coroutines
所谓协程,是一个函数,能在保持状态的时候暂停或者继续。具有关键字:
- co_await:挂起协程,等待其它计算完成
- co_return:退出协程
- co_yield:弹出一个值,挂起协程,等待下一次调用,类似于Python中的生成器
待补充内容
Modules
关键字:import,export
新建测试文件test_module.ixx和main.cpp,注意模块文件后缀名为.ixx,如果为.cpp文件可能需要去命令行编译,使用方式和include差不多,但是说使用模块比使用include效率要高很多:
// test_module.ixx
export module test_module;
namespace _module {
auto _print() { return "hello world"; }
export auto print() { return _print(); }
} // namespace _module
/*——————————————————————————————————————————*/
// main.cpp
import test_module;
#include <iostream>
int main() {
std::cout << _module::print() << std::endl; // hello world
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
模块优势:
- 没有头文件
- 声明和实现仍然可以分离,但没有必要
- 可以显式指定导出目标对象(函数,类)
- 没有头文件重复包含风险
- 模块名称可以相同
- 模块只处理一次,编译更快(头文件每次引入都需要处理)
- 预处理宏只在模块内有效
- 模块引入顺序无关紧要
Core Language
特性测试宏
通过它可以判断编译器是否支持某个功能,例如:
// 语言特性
__has_cpp_attribute(fallthrough)
__cpp_binary_literals
__cpp_char8_t
__cpp_coroutines
// 标准库特性
__cpp_lib_concepts
__cpp_lib_ranges
__cpp_lib_scoped_lock
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
三路比较运算符<=>
(x <=> y) < 0 // 如果 x < y, 返回 true
(x <=> y) > 0 // 如果 x > y, 返回 true
(x <=> y) == 0 // 如果 x == y, 返回 true
1
2
3
2
3
可以使用以下代码代替所有的比较运算符:
auto X::operator<=>(const X&) = default;
1
范围for循环初始化
class Data {
public:
Data(){}
Data getData() { return Data(); }
private:
std::vector<int> values;
};
int main() {
for (auto data = getData(); auto &value : data.values) {
cout << value << " ";
}
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16