C++20 是 C++ 语言的一次重要更新,引入了大量新特性,从语言层面和标准库方面进行了诸多改进。新版本的发布为 C++ 程序员带来了更高的灵活性、可读性和性能。在这篇博客中,我们将深入探讨 C++20 中的一些重要特性,包括 Concepts(概念)、Ranges(范围库)、Coroutines(协程)、三方比较运算符(<=>)、Modules(模块)以及更多值得关注的改进。
### 文章目录
- [@[toc]](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [一、Concepts(概念)](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [示例](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [二、Ranges(范围库)](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [示例](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [三、Coroutines(协程)](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [示例](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [四、三向比较运算符(<=>)](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [示例](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [五、Modules(模块)](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [示例](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [六、扩展特性与改进](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [1. **范围 `for` 循环的 `initializer` 支持**](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [2. **`std::span`**](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结) - [总结](#文章目录 @[toc] 一、Concepts(概念) 示例 二、Ranges(范围库) 示例 三、Coroutines(协程) 示例 四、三向比较运算符(<=>) 示例 五、Modules(模块) 示例 六、扩展特性与改进 1. 范围
for
循环的initializer
支持 2.std::span
总结)
一、Concepts(概念)
Concepts 是 C++20 中模板编程的一大增强。传统的模板编程在遇到模板类型不满足需求时,会产生复杂的错误信息,导致编译时间延长。Concepts 旨在通过为模板参数添加约束条件,从而限制模板的类型,提高代码的可读性和安全性。
示例
cpp
#include <concepts>
#include <iostream>
template <typename T>
concept Number = std::integral<T> || std::floating_point<T>;
template <Number T>
T add(T a, T b) {
return a + b;
}
int main() {
std::cout << add(1, 2) << std::endl; // 可以编译
// std::cout << add("hello", "world"); // 编译失败,不满足 Number 概念
return 0;
}
在这个例子中,Number
是一个概念,用于约束 add
函数的模板参数,使其只能接受整数或浮点数,而不能接受其他类型。Concepts 使得错误信息更加清晰,有助于快速定位问题,优化了模板编程体验。
二、Ranges(范围库)
Ranges 是 C++20 中标准库新增的一部分,旨在简化容器的操作,让代码更加清晰和直观。通过 Ranges 库,我们可以用链式的方式对容器执行多种操作,避免了中间变量的创建,提高了代码的可读性和性能。
示例
cpp
#include <iostream>
#include <ranges>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5, 6};
// 使用 Ranges 库筛选和转换数据
auto result = vec | std::views::filter([](int n) { return n % 2 == 0; })
| std::views::transform([](int n) { return n * n; });
for (int n : result) {
std::cout << n << " "; // 输出: 4 16 36
}
return 0;
}
在这个例子中,我们通过 filter
筛选出偶数,然后使用 transform
将每个偶数平方。Ranges 让我们可以以流式、链式的方式操作容器,避免使用多层循环和冗长的迭代器代码,从而使代码更加简洁。
三、Coroutines(协程)
协程 是 C++20 中的一个重要特性,允许函数在执行过程中挂起并恢复,而不需要阻塞线程。协程特别适合用于异步编程、生成器和迭代器等场景。
示例
cpp
#include <coroutine>
#include <iostream>
#include <memory>
struct Generator {
struct promise_type {
int current_value;
auto get_return_object() { return Generator{this}; }
auto initial_suspend() { return std::suspend_always{}; }
auto final_suspend() noexcept { return std::suspend_always{}; }
void return_void() {}
auto yield_value(int value) {
current_value = value;
return std::suspend_always{};
}
void unhandled_exception() { std::terminate(); }
};
using handle_type = std::coroutine_handle<promise_type>;
handle_type coro_handle;
explicit Generator(promise_type* p)
: coro_handle(handle_type::from_promise(*p)) {}
~Generator() { coro_handle.destroy(); }
bool move_next() {
coro_handle.resume();
return !coro_handle.done();
}
int current_value() { return coro_handle.promise().current_value; }
};
Generator counter() {
for (int i = 0; i < 5; ++i)
co_yield i;
}
int main() {
auto gen = counter();
while (gen.move_next()) {
std::cout << gen.current_value() << " ";
}
return 0;
}
协程提供了关键字 co_yield
和 co_return
,用于生成值并挂起执行,使函数可以在需要时恢复。协程的优势在于,它可以在需要时暂停和恢复,提供了更好的性能和灵活性,特别是在异步和并发场景中。
四、三向比较运算符(<=>)
C++20 引入了三向比较运算符(<=>),也称为"飞船运算符",使比较操作更加简洁。该运算符可以自动生成 <
, >
, <=
, >=
等操作符,实现了更具表现力的排序功能。
示例
cpp
#include <iostream>
#include <compare>
struct Person {
std::string name;
int age;
auto operator<=>(const Person&) const = default;
};
int main() {
Person alice{"Alice", 30};
Person bob{"Bob", 25};
if (alice < bob)
std::cout << "Alice is younger than Bob" << std::endl;
else
std::cout << "Alice is older than or the same age as Bob" << std::endl;
return 0;
}
三向比较运算符允许我们直接通过 operator<=>
生成所有的比较运算符,省去了手动定义多个比较函数的麻烦。对于类似 Person
这样的结构体,使用默认的 <=>
可以自动生成默认的成员比较功能。
五、Modules(模块)
模块 是 C++20 引入的另一个重要特性,旨在替代传统的头文件,减少编译时间,提升代码的模块化和封装性。传统的头文件引入了大量的重复编译,而模块可以避免这种情况,通过更高效的方式组织代码。
示例
模块的使用分为模块定义和模块导入两个部分。
cpp
// math_module.ixx (模块定义)
export module math_module;
export int add(int a, int b) {
return a + b;
}
// main.cpp (模块导入)
import math_module;
#include <iostream>
int main() {
std::cout << add(1, 2) << std::endl;
return 0;
}
在上面的例子中,我们定义了一个 math_module
模块,并导入该模块以使用其中的 add
函数。模块提高了代码的可维护性,减少了编译时间,避免了传统头文件的多次包含带来的问题。
六、扩展特性与改进
除了上述几个核心特性,C++20 还引入了一些其他实用的新特性:
1. 范围 for
循环的 initializer
支持
在 C++20 中,范围 for
循环支持初始化器,这使得我们可以在循环中定义临时变量,简化了代码结构。
cpp
#include <vector>
#include <iostream>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
for (auto it = vec.begin(); auto& value : vec) {
std::cout << value << " ";
}
return 0;
}
2. std::span
std::span
是 C++20 引入的轻量级视图,用于处理一段连续的内存。它不拥有数据,仅作为对数据的一个"窗口"或"视图"。std::span
可以用来替代传统的指针和大小参数组合,使得接口更加安全和直观。
cpp
#include <span>
#include <iostream>
void print(std::span<int> data) {
for (int value : data) {
std::cout << value << " ";
}
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
print(arr);
return 0;
}
std::span
提供了方便的数据访问方式,同时避免了指针的使用,提高了接口的安全性。
总结
C++20 的发布为 C++ 带来了许多变革性的特性,极大地提升了语言的可用性和表达能力。从 Concepts 到 Modules,再到协程和 Ranges,C++20 提供了更强大的工具来处理现代编程中的各种挑战。