首页 互联网资讯 曾被“劝退”的 C++ 20 正式发布!

曾被“劝退”的 C++ 20 正式发布!

互联网资讯 874

原标题:曾被“劝退”的 C++ 20 正式发布!

【编者按】近日,C++20 标准正式公布,这不禁让人想起了 2018 年年底 C++ 标准委员会讨论 C++ 20 新特性的光景。

当时“ C++ 20 还未发布,就已凉凉? ”的论调可谓火热,其中 C++ 模块化更是引起了国内外开发者的嫌弃:C++ 开发者怒了:这个无用的模块设计最终会害死 C++!

这个未出世就被群嘲“劝退”的 C++20 ,如今终于正式发布,那它带来了哪些新特性呢?一起来看大佬实战探究总结!

作者 | 连少华 责编 |张文

近日,ISO C++委员会正式发布了 C++20 标准,命名为 ISO/IEC 14882:2020。

作为程序员,看到新标准发布总想尝鲜,目前 gcc 10.2 可以支持部分 C++ 20 标准,编译的时候需要使用编译选项:-std=c++2a。

Constraints and concepts (约束和概念)

在类模板和函数模板编程中,主要用于对模板参数的结束和限制,这种约束和限制发生在编译期,编译错误不再那么晦涩难懂了。

在模板编程中,可以限制模板参数的类型或具用某种特性,如:可以限制为整型、数值型、bool 型、或必须支持 hash 特性、或某个类的派生类型等。

在 C++20 中 Concepts 是非常重要的概念,模板编程终于有了质的提升。

Concepts

Concepts 是 requirements 的 具名集合,concepts 需要声明在命名空间中,语法如下:

template< template-parameter- list> concept concept-name = constraint-expression;

如下所示:

template< typenameT> concept Hashable = requires(T a) { { std::hash<T>{}(a) } -> std::convertible_to< std:: size_t>; }; //声明了一个名为Hashable的concept

structmeow{ };

template<Hashable T> voidf(T); // 约束这个T必须满足Hashable concept,否则无法编译通过。

intmain{ f( "abc"s); // OK,string是可hash的f(meow{}); // Error: meow结构体不是可hash的,当然可以让其支持hash。}//template< typenameT> concept C= sizeof(T)> 10;

template<C T> classtest{ }; template<C T> voidfunc(T t);

Constraints

约束是逻辑操作和操作数的序列,它用于指定对模板实参的要求。可在 requires 表达式中出现,也可直接作为 concept 的主体。

有三种类型的约束:

合取(conjunction)

析取(disjunction)

原子约束(atomic constraint)

如下所示:

template<Incrementable T>voidf(T)requiresDecrementable<T> ;

template<Incrementable T>voidf(T)requiresDecrementable<T> ; // OK:重声明

Requires

requires 用于约束模板参数或具体的参数。

requires 子句

如下所示:

template<typename T>voidf(T&&)requiresEq<T> ; // 可作为函数声明符的最末元素出现

template<typename T> requiresAddable<T> // 或在模板形参列表的右边T add(T a, T b){ returna + b; }

关键词 requires 必须后随某个常量表达式(故可以写为 requires true),但其意图是 使用某个具名概念(如上例),或 具名概念的一条合取/析取,或一个 requires 表达式。

表达式必须具有下列形式之一:

初等表达式,例如 Swappable、std::is_integral::value、(std::is_object_v && …) 或任何带括号表达式

以运算符 && 连接的初等表达式的序列

以运算符 || 连接的前述表达式的序列

requires 表达式

语法如下:

requires{ requirement-seq } requires( parameter-list(optional) ) { requirement-seq }

parameter-list - 与函数声明中类似的形参的逗号分隔列表,但 不允许默认实参且不能以(并非指定包展开的)省略号结尾。这些形参无存储期、连接或生存期,它们仅用于辅助进行各个要求的制定。这些形参在要求序列的闭 } 前处于作用域中。

requirement-seq - 要求(requirement)的序列,描述于下(每个要求以分号结尾)。

requirement-seq 中的每个要求必须是下面的四项之一:

简单要求(simple requirement)

类型要求(type requirement)

复合要求(compound requirement)

嵌套要求(nested requirement)

如下所示:

template<typename T>concept Addable = requires (T x) { x + x; }; // requires 表达式

template<typename T> requires Addable<T> // requires 子句,非 requires 表达式T add(T a, T b) { return a + b; }

template<typename T>requires requires (T x) { x + x; } // 随即的约束,注意关键字被使用两次T add(T a, T b) { return a + b; }

Modules (模块)

用于 从逻辑上划分代码,能够加快编译速度,并且与导入的顺序无关(还记得以前由于 #include 顺序的不同导致的编译错误吗?)

主要有三个关键字:

module:用于声明一个模块

export:用于导出模块、函数或类

import:用于导入模块

如下所示:

定义了一个 helloworld 模块,导出了 hello 函数

//helloworld.cppexportmodulehelloworld; // module declarationimport<iostream>; // import declaration exportvoidhello{ // export declarationstd:: cout<< "Hello world!n"; } //main.cppimport helloworld;

int main{hello;}

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( intn = 0) { while( true) co_yield n++; //与 Python 中的 yield 类似}

co_return

co_return 用于结束当前协程的执行并返回一个值

lazy< int> f( ) { co_return 7; }

当然协程也有一些限制:

不能使用变长实参;

不能使用普通的 return 语句,或占位符返回类型(auto 或 Concept);

constexpr 函数、构造函数、析构函数及 main 函数不能是协程。

Ranges(范围)

提供了处理基于范围的元素(可简单理解为容器)的组件及各种适配器,还有一些新的算法。

主要有如下几类:

基于范围的访问器

基于范围的原语

基于范围的 concept

视图

工厂

适配器

详见头文件:

一个简单的例子:

# include<vector># include<ranges># include<iostream>intmain{std:: vector< int> ints{ 0, 1, 2, 3, 4, 5}; autoeven = []( inti){ return0== i % 2; }; autosquare = []( inti) { returni * i; }; for( inti : ints | std::views::filter(even) | std::views::transform(square)) { std:: cout<< i << ' '; }}

Designated Initializers(指定初始化)

使用 {} 初始化数组、类、结构体或联合等的成员。

structA{ inta; intb; intc;}; A a{.a= 10,.b= 100,.c= 20}; operator<=>

三路比较运算符,形如:

lhs < => rhs

其行为如下:

(a <=> b) < 0iflhs < rhs (a <=> b) > 0iflhs > rhs (a <=> b) == 0iflhs equal rhs

示例如下:

# include<compare># include<iostream>intmain{ doublefoo = -0.0; doublebar = 0.0; autores = foo <=> bar; if(res < 0) std:: cout<< "-0 is less than 0"; elseif(res == 0) std:: cout<< "-0 and 0 are equal"; elseif(res > 0) std:: cout<< "-0 is greater than 0"; }

Attributes(特性)

[[nodiscard( string-literal )]]:忽略返回值时警告。

[[likely]] 和[[unlikely]]:指示编译器优化更可能出现的情况或分支。是一种对变量值出现可能性的一种预判。

intf( inti ) {if(i < 0) [[unlikely]] { return0; }return1; }

3.[[no_unique_address]]:用于优化存储空间,当成员为空的时候可以不占用存储空间

Others

constexpr 新增对虚函数的支持。char8_t 用于存储utf-8的字符串。constinit

强制常量初始化,不可以动态初始化

constchar* g{ return"dynamic initialization"; } constexprconstchar* f( boolp) { returnp ? "constant initializer": g; } constinit constchar* c = f( true); // OKconstinit constchar* d = f( false); // error labmda

不再支持以值的形式默认捕获参数;

允许以值的形式显示捕获 this;

支持模板,且支持可变参数;

template< typename... Args> voidfoo(Args... args){ [...xs=args]{bar(xs...); // xs is an init-capture pack};} std::format

使用 {} 进行格式化字符串,再也不用恶心的 stream 来拼接了,之前使用过boost 的 format,同样好用。

# include<iostream># include<format>intmain{ std:: cout<< std::format( "Hello {}!n", "world"); } std::span

span 是容器的视图(即不拥有),提供对连续元素组的边界检查访问。因为视图不拥有自己的元素,所以构造和复制的成本很低;

std::jthread

新的线程类,与 std::thread 类似,只是功能更强大,支持停止、自动 join 等

Calendar 和 time zoneendian 用于判断大小端的枚举std::make_shared 支持数组atomic 支持浮点数和 smart ptrstd::basic_syncbuf 和 std::basic_osyncstreamstring 增加 starts_with 和 end_with 函数std::atomic_ref 原子引用std::to_array 将 xxx 转换为 std::arrayinline namespace

特性概览

核心功能特性概览

library features

更多标准功能详情,大家也可以移步至 C++ 官方发布平台查看。

https://en.cppreference.com/w/cpp/20 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2131r0.html

草案版本:

https://github.com/cplusplus/draft/tree/c++20

作者简介:连少华,资深架构师。钟爱 C++语言,是 C++语言的资深研究者,对新技术有敏锐洞察和见解,拥有十多年一线软件架构设计和开发经验,先后在中兴通讯、深交所和金证股份任职资深开发和架构师,同时负责软件架构的设计和核心编码。目前在互联网金融企业主导公司交易系统、行情系统和量化系统的设计与开发。先后翻译了《C++代码整洁之道》和《Python 代码整洁之道》。 。

CRM软件收集

本站声明:本文内容来源于曾被“劝退”的 C++ 20 正式发布!,如有侵权,请联系我们,我们将及时处理。