大家好,我是大李。
最新的C++版本是C++20,你有了解过C++20添加了哪些新特性吗?
1 模块(Modules)
改变了组织源码文件的方式,无需再区分.h 和.cpp 文件。
2 协程(Coroutines)
可以暂停执行然后在未来的某个时间点恢复执行的函数,能方便地编写异步代码。
在 C++20 中,可以使用 库中的相关函数来实现暂停执行然后在未来某个时间点恢复执行,方便地编写异步代码。
// 定义一个异步任务的协程
#include <coroutine>
#include <iostream>
#include <chrono>
struct AsyncTask {
struct promise_type {
AsyncTask get_return_object() { return AsyncTask{Handle::from_promise(*this)}; }
std::suspend_always initial_suspend() { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
void return_void() {}
void unhandled_exception() {}
};
using Handle = std::coroutine_handle<promise_type>;
AsyncTask(Handle h) : handle(h) {}
Handle handle;
};
AsyncTask asyncOperation() {
std::cout << "任务开始" << std::endl;
co_await std::suspend_always{};
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "任务恢复执行" << std::endl;
}
int main() {
AsyncTask task = asyncOperation();
task.handle.resume();
}
在上述示例中,
asyncOperation
函数是一个异步任务,通过co_await std::suspend_always{}
实现了暂停执行。在 main 函数中,通过task.handle.resume()
来恢复执行。
3 范围(Ranges)
提供了类似于迭代器的功能,且具有类型安全特性,其相关概念——管道操作符可提升代码可读性,并且直接进行惰性计算,不会产生中间数组。以下是关于范围的示例:
范围 for 循环
std::vector<int> numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
std::cout << num << " ";
}
使用范围算法
#include <ranges>
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 过滤出偶数
auto evenNumbers = numbers | std::views::filter([](int num) { return num % 2 == 0; });
for (int num : evenNumbers) {
std::cout << num << " ";
}
}
范围转换
#include <ranges>
#include <iostream>
#include <vector>
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 将每个数乘以 2
auto doubledNumbers = numbers | std::views::transform([](int num) { return num * 2; });
for (int num : doubledNumbers) {
std::cout << num << " ";
}
}
范围的引入大大简化了对数据集合的操作,提高了代码的可读性和简洁性。
4 概念与约束
用于对模板参数进行更灵活的限制和约束,减小了对模板类型的限制,使模板参数的限制和规范在编译期更清晰、灵活。
5 指定初始化
提供了更灵活的对象初始化方式。
类内成员初始化的改进
class MyClass {
int member1{42}; // 直接初始化成员
std::string member2 = "Hello"; // 初始化字符串成员
};
使用 std::initializer_list 进行初始化
class Container {
public:
Container(std::initializer_list<int> values) {
for (auto value : values) {
// 处理初始化列表中的值
}
}
};
Container c = {1, 2, 3}; // 使用初始化列表初始化对象
委托构造函数
class MyClass {
public:
MyClass(int x, int y) : data{x + y} {}
MyClass(int x) : MyClass(x, 0) {} // 委托给另一个构造函数
private:
int data;
};
这些新的初始化方式使得代码更加简洁、直观,并且提高了代码的可读性和可维护性。
6 操作符
<=> 操作符用于定义三路比较,!=== 是一个新的不等于操作符。
<=>
它主要用于为自定义类型提供一种简洁且统一的比较方式。
通过定义 <=> 运算符,你可以方便地确定两个对象之间的顺序关系。
返回值类型通常是 std::strong_ordering
、 std::weak_ordering
或 std::partial_ordering
。
std::strong_ordering::less
:表示左边的对象小于右边的对象。
std::strong_ordering::greater
:表示左边的对象大于右边的对象。
std::strong_ordering::equal
:表示两个对象相等。
!===
它的作用类似于传统的 !=
运算符,但在某些情况下可能提供更清晰和明确的语义表达。
7 constexpr 支持
扩展了 constexpr 在 new/delete、dynamic_cast、try/catch、虚拟等方面的能力。
8 constexpr 向量和字符串
可以在常量表达式中使用向量和字符串。
#include <iostream>
#include <string>
#include <vector>
consteval std::vector<int> createVector() {
return {1, 2, 3};
}
consteval std::string createString() {
return "Hello, C++20!";
}
int main() {
constexpr auto vec = createVector();
constexpr auto str = createString();
for (const auto& num : vec) {
std::cout << num << " ";
}
std::cout << std::endl;
std::cout << str << std::endl;
return 0;
}
在上述示例中,
createVector
函数和createString
函数被标记为consteval
,表示它们在常量表达式中计算并返回一个向量和一个字符串。然后在 main 函数中,以常量表达式的方式使用这些返回值。
9 计时
增加了日历、时区支持。可以使用 库的新特性来实现计时功能。
#include <iostream>
#include <chrono>
int main() {
// 开始计时
auto start = std::chrono::steady_clock::now();
// 执行一些耗时操作
for (int i = 0; i < 1000000; ++i) {
// 一些计算或操作
}
// 结束计时
auto end = std::chrono::steady_clock::now();
// 计算时间差
std::chrono::duration<double> elapsed_seconds = end - start;
std::cout << "耗时: " << elapsed_seconds.count() << " 秒" << std::endl;
return 0;
}
在上述示例中,使用
std::chrono::steady_clock::now()
获取当前时间点,然后通过计算时间差来得到操作所花费的时间。
关于C++20的新特性还有哪些呢?欢迎留言讨论!!!
往期精选
-
我做了个C++算法学习网站 -
CSP-J 信息学复习指南 -
「简单数论」初赛考察的数学知识
本文由 mdnice 多平台发布