关于C++20新特性及其使用

大家好,我是大李。

最新的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_orderingstd::weak_orderingstd::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的新特性还有哪些呢?欢迎留言讨论!!!

往期精选

本文由mdnice多平台发布

相关推荐
津津有味道38 分钟前
Qt C++串口SerialPort通讯发送指令读写NFC M1卡
linux·c++·qt·串口通信·serial·m1·nfc
傅里叶的耶1 小时前
C++系列(二):告别低效循环!选择、循环、跳转原理与优化实战全解析
c++·visual studio
Vitta_U1 小时前
MFC的List Control自适应主界面大小
c++·list·mfc
Dovis(誓平步青云)2 小时前
基于探索C++特殊容器类型:容器适配器+底层实现原理
开发语言·c++·queue·适配器·stack
pipip.4 小时前
UDP————套接字socket
linux·网络·c++·网络协议·udp
孞㐑¥8 小时前
Linux之Socket 编程 UDP
linux·服务器·c++·经验分享·笔记·网络协议·udp
水木兰亭11 小时前
数据结构之——树及树的存储
数据结构·c++·学习·算法
CoderCodingNo12 小时前
【GESP】C++四级考试大纲知识点梳理, (7) 排序算法基本概念
开发语言·c++·排序算法
秋风&萧瑟14 小时前
【C++】C++中的友元函数和友元类
c++
梁诚斌14 小时前
使用OpenSSL接口读取pem编码格式文件中的证书
开发语言·c++