C++20的四大新特性

C++20(C++ 编程语言标准 2020 版)将是 C++ 语言一次非常重大的更新,将为这门语言引入大量新特性。近日,C++ 开发者 Rainer Grimm 正通过一系列博客文章介绍 C++20 的新特性。目前这个系列文章已经更新了两篇,本篇是第一篇,主要介绍了 C++20 的 Big Four(四大新特性:概念、范围、协程和模块)以及核心语言(包括一些新的运算符和指示符)。

C++20 的编译器支持

适应新特性的最简单方法是试用它们。那么接下来我们就面临着这个问题:哪些编译器支持 C++20 的哪些特性?一般来说,cppreference.com/compiler_support_能提供在核心语言和库方面的答案。

简单来说,全新的 GCC、Clang 和 EDG 编译器能提供对核心语言的最佳支持。此外,MSVC 和 Apple Clang 编译器也支持许多 C++20 特性。

C++20 核心语言特征。

库方面的情况类似。GCC 在库方面的支持最好,接下来是 Clang 和 MSVC 编译器。

C++20 库特征。

上面的截图仅展示了对应表格的前面一部分,可以看出这些编译器的表现并不是非常令人满意。即使你使用的是全新的编译器,这些编译器仍然不支持很多新特性。

通常来说,你能找到尝试这些新特性的方法。下面是两个示例:

  • 概念:

GCC 支持概念的前一个版本;

  • std::jthread:

GitHub 上有一个实现草案,来自 Nicolai Josuttis:

https://github.com/josuttis/jthread

简单来说,问题没有那么严重。只需要一些调整修改,很多新特性就能进行尝试。如有必要,我会提到如何进行这样的修改。

四大新特性

概念(concept)

使用模板进行通用编程的关键思想是定义能通过各种类型(type)使用的函数和类。但是,在实例化模板时经常会出现用错类型的问题,其结果通常是几页难懂的报错信息。

现在概念来了,这个问题可以休矣。概念让你能为模板编写要求,而编译器则可以检查这个要求。概念革新了我们思考和编写通用代码的方式。原因如下:

  • 模板的要求是接口的一部分;
  • 类模板中的函数重载或特殊化可以基于概念进行;
  • 因为编译器能够比较模板参数的要求与实际的模板参数,所以能得到更好的报错信息。

但是,这还不是全部。

  • 你可以使用预定义的概念,也可以定义你自己的概念;
  • auto 和概念的用法统一到了一起。你可以不使用 auto,而是使用概念;
  • 如果一个函数声明使用了一个概念,那么它会自动变成一个函数模板。由此,编写函数模板就变得与编写函数一样简单。

下面的代码片段展示了一个简单概念 Integral 的定义和使用方式:

template<typename T> concept bool Integral()
{     
    return std::is_integral<T>::value; 
}  
Integral auto gcd(Integral auto a,Integral auto b)
{     
    if( b == 0 ) return a;     
    else return gcd(b, a % b); 
} 

Integral 这个概念需要 std::is_integral<T>::value 中的类型参数 T。std::is_integral<T>::value 这个函数来自 type-traits 库,它能在 T 为整数检查编译时间。如果 std::is_integral<T>::value 的值为 true,则没有问题。如果不为 true,则你会收到一个编译时间报错。如果你很好奇(你也应该好奇),我的这篇文章介绍了 type-traits 库:https://www.modernescpp.com/index.php/tag/type-traits。

gcd 算法是基于欧几里德算法确定最大公约数(greatest common divisor)。我使用了这个缩写函数模板句法来定义 gcd。gcd 要求其参数和返回类型支持概念 Integral。gcd 是一类对参数和返回值都有要求的函数模板。当我删除这个句法糖(syntactic sugar)时,也许你能看到 gcd 的真正本质。

下面这段代码在语义上与 gcd 算法等效:

template<typename T>  
requires Integral<T>()  
T gcd(T a, T b)
{      
    if( b == 0 ) return a;       
    else return gcd(b, a % b);  
} 

如果你还没看到 gcd 的真正本质,过几周我还会专门发布一篇介绍概念的文章。

范围库(Ranges Library)

范围库是概念的首个客户。它支持的算法满足以下条件:

可以直接在容器上操作;无需迭代器指定一个范围;

可以宽松地评估;

可以组合。

简单来说:范围库支持函数模式(functional patterns)。

代码可能比语言描述更清楚。下面的函数用竖线符号展示了函数组成:

#include <vector>  
#include <ranges>  
#include <iostream>  
int main()
{    
    std::vector<int> ints{0, 1, 2, 3, 4, 5};    
    auto even = [](int i)
    { return 0 == i % 2; };    
    auto square = [](int i) 
    { return i * i; };    
    for (int i : ints | std::view::filter(even) | std::view::transform(square)) 
    {      
        std::cout << i << ' ';            // 0 4 16   
    }  
}                      

even 是一个 lambda 函数,其在 i 为偶数时返回;lambda 函数 square 则会将 i 映射为它的平方。其余的必须从左到右读取的第 i 个函数组成:for (int i : ints | std::view::filter(even) | std::view::transform(square)). 将过滤器 even 应用于 ints 的每个元素,然后将其余的每个元素映射为它们的平方。如果你熟悉函数编程,那么这读起来就像一篇散文诗。

Coroutines(协程)

协程,就是能够暂停执行然后在接下来的某个时间点恢复执行的函数,C++中的协程是无栈的(stack less)。使用协程可以方便的编写异步代码(和编写同步代码类似)。

主要涉及三个关键字:

  • co_await
    co_await暂停当前协程的执行,直到等待的操作完成后继续执行。
task<> tcp_echo_server() {
  char data[1024];
  for (;;) {
    std::size_t n = co_await socket.async_read_some(buffer(data)); #与 Python 中的 await 类似
    co_await async_write(socket, buffer(data, n));
  }
}

上述代码,在async_read_some()完成后,继续执行下面的语句,在 async_read_some()执行完成之前,暂停执行并让出控制权。

  • co_yield
    co_yield暂停执行并返回一个值,与return不同的是co_yield虽然返回了值 ,但当前函数没有终止。
    generator<int> iota(int n = 0) {
      while(true)
        co_yield n++;  //与 Python 中的 yield 类似
    }
    

     

  • co_return
    co_return 用于结束当前协程的执行并返回一个值lazy<int> f() { co_return 7; }
  • lazy<int> f() {
      co_return 7;
    }
    

    当然协程也有一些限制:

  • 不能使用变长实参
  • 不能使用普通的 return 语句,或占位符返回类型(auto 或 Concept)
  • constexpr 函数、构造函数、析构函数及 main 函数 不能是协程
  •  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

靠谱码农阿杰

你们的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值