全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2020-01-12_解读C++即将迎来的重大更新(二):C++20的核心语言

您的位置:首页 >> 新闻 >> 行业资讯

解读C++即将迎来的重大更新(二):C++20的核心语言 选自modernescpp 作者:JP Tech等 机器之心编译 参与:Panda、杜伟 C++20(C++ 编程语言标准 2020 版)将是 C++ 语言一次非常重大的更新,将为这门语言引入大量新特性。C++ 开发者 Rainer Grimm 通过一系列博客文章介绍 C++20 的新特性。目前这个系列文章已经更新了两篇,本篇是第二篇,主要介绍了 C++20 的核心语言(包括一些新的运算符和指示符)。 C++20 的核心语言之前的一篇博客概览式地介绍了 C++20 的概念、范围、协程和模块,下面开始介绍它的核心语言。 三路比较运算符 三路比较运算符 通常被称为太空船运算符。飞船运算符能确定两个值 A 和 B 谁大谁小或相等。编译器可以自动生成三路比较运算符。你只需要用 default 礼貌地要求它即可。在这种情况下,你会得到所有六种比较运算符:==、!=、=、=。 #includecompare structMyInt{ intvalue; MyInt(intvalue):value{value}{} autooperator(constMyIntconst=default; }; 默认的 执行的是字典顺序比较(lexicographical comparison),使用从基类开始从左到右并以声明顺序(declaration order)使用非静态元素的顺序。 微软的博客上有一些相当复杂精细的示例:https://devblogs.microsoft.com/cppblog/simplify-your-code-with-rocket-science-c20s-spaceship-operator/ structBasics{ int char float double autooperator(constBasicsconst=default; }; structArrays{ intai[1]; charac[2]; floataf[3]; doublead[2][2]; autooperator(constArraysconst=default; }; structBases:Basics,Arrays{ autooperator(constBasesconst=default; }; intmain(){ constexprBasesa={{0,'c',1.f,1.}, {{1},{'a','b'},{1.f,2.f,3.f},{{1.,2.},{3.,4.}}} constexprBasesb={{0,'c',1.f,1.}, {{1},{'a','b'},{1.f,2.f,3.f},{{1.,2.},{3.,4.}}} static_assert(a== static_assert(!(a!= static_assert(!(a static_assert(a= static_assert(!(a static_assert(a= } 我认为,这个代码段中最复杂的部分不是太空船运算符,而是使用聚合初始化(aggregate initialisation)来实现 Base 的初始化。聚合初始化本质上意味着如果所有元素是公开的,那么你可以直接初始化类类型(class、struct 或 union)的元素。在这个案例中,你可以使用示例中那样的 braced-initialisation-list。好吧,这确实经过了简化,详见:https://en.cppreference.com/w/cpp/language/aggregate_initialization将字符串文字作为模板参数在 C++20 之前,你不能将字符串用作非类型的模板参数。使用 C++20 时,你则可以这么做。我们可以在标准定义的 basic_fixed_string 中使用它们,其有一个 constexpr 构造函数。这个 constexpr 构造函数能在编译时实例化这个固定字符串。 templatestd::basic_fixed_stringT classFoo{ staticconstexprcharconst*Name= public: voidhello()const; }; intmain(){ Foo"Hello!"foo; foo.hello(); } constexpr 虚拟函数 由于动态类型是未知的,所以无法在常量表达式(constant expression)中调用虚拟函数。这个限制将在 C++20 中被解除。 指定初始化器 我首先谈谈聚合初始化。下面是一个简单示例: //aggregateInitialisation.cpp #includeiostream structPoint2D{ int int }; classPoint3D{ public: int int int }; intmain(){ std::coutstd::endl; Point2Dpoint2D{1,2}; Point3Dpoint3D{1,2,3}; std::cout"point2D:"point2D.x""point2D.ystd::endl; std::cout"point3D:"point3D.x""point3D.y""point3D.zstd::endl; std::coutstd::endl; } 我认为无需对这个程序进行解释。看看这个程序的输出: 显式总比隐式好。我们看看这是什么意思。程序 aggregateInitialisation.cpp 中的初始化非常容易出错,因为你可能写反这个构造函数的参数,而且你永远没法察觉。来自 C99 的指定初始化器就能在这里大显身手了。 //designatedInitializer.cpp #includeiostream structPoint2D{ int int }; classPoint3D{ public: int int int }; intmain(){ std::coutstd::endl; Point2Dpoint2D{.x=1,.y=2}; //Point2Dpoint2d{.y=2,.x=//(1)error Point3Dpoint3D{.x=1,.y=2,.z=2}; //Point3Dpoint3D{.x=1,.z=2}//(2){1,0,2} std::cout"point2D:"point2D.x""point2D.ystd::endl; std::cout"point3D:"point3D.x""point3D.y""point3D.zstd::endl; std::coutstd::endl; } 实例 Point2d 和 Point3D 的参数从名称就能看出来。这个程序的输出就等同于程序 aggregateInitialisation.cpp 的输出。带注释(1)和(2)的行很有意思。行(1)会报错,因为指定器的顺序与它们的声明顺序不匹配。在(3)行中,y 的指定器缺失了。在这个案例中,y 会被初始化为 0,比如使用 braces-initialisation-list {1, 0, 3}.对 lambda 的各种改进C++20 在 lambda 方面的改进也很多。如果你想要了解改动的细节,请参阅 Bartek 的博客:https://www.bfilipek.com/2019/02/lambdas-story-part1.html,里面介绍了 C++17 和 C++20 中的 lambda 改进。总之,我们会迎来两个有意思的变化。允许 [=, this] 作为 lambda capture,并通过 [=] 弃用这个的隐式 capture structLambda{ autofoo(){ return[=]{std::coutsstd::endl; } std::string }; structLambdaCpp20{ autofoo(){ return[=,this]{std::coutsstd::endl; } std::string }; 在 C++20 中,通过在结构体 lambda 中复制而实现隐式 [=] capture 会出现弃用警告。如果你通过复制 [=, this] 来显式地获取它,就不会收到 C++20 的弃用警告。模板 lambda 你可能和我一样,最先想到的是:我们为什么需要模板 lambda?当你用 C++14 的 [](auto x){ return x; } 写一个通用 lambda 时,编译器会自动使用一个模板化的调用运算符来生成一个类: templatetypenameT Toperator(Tx)const{ return } 有时候,你想要定义一个只对某个特定类型(如 std::vector)有效的 lambda。现在,模板 lambda 能帮我们做到这一点。你可以不使用类型参数,而是使用概念: autofoo=[]typenameT(std::vectorconstvec){ //dovectorspecificstuff 新属性:[[likely]] 和 [[unlikely]]C++20 有 [[likely]] 和 [[unlikely]] 两个新属性。这两个新属性都允许为优化器提供提示:执行的路径是更可能或是更不可能。 for(size_ti=0;iv.size();++i){ if(unlikely(v[i]0))sum-=sqrt(-v[i]); elsesum+=sqrt(v[i]); } 指示符 consteval 和 constinit新的指示符 consteval 会创建一个即时函数。对于一个即时函数,每一次函数调用都必然产生一个编译时常量表达式。即时函数是隐式的 constexpr 函数。 constevalintsqr(intn){ return } constexprintr=sqr(100);//OK intx=100; intr2=sqr(x);//Error 因为 x 不是常量表达式,所以最后的赋值会出错。因此,编译时不会执行 sqr(x)。constinit 会确保有静态存储持续的变量在编译时被初始化。静态存储持续(static storage duration)的意思是对象会在程序开始时分配,在程序结束时又会重新分配。对于命名空间范围内声明的对象(全局对象),声明为 static 或 extern 的对象有静态存储持续。std::source_location C++11 有两个宏 __LINE__ 和 __FILE__ 来获取代码行和文件的信息。而在 C++20 中,类 source_location 能提供有关源代码的文件名、行号、列号和函数名信息。下面这个来自 cppreference.com的示例展示了第一种用途: #includeiostream #includestring_view #includesource_location voidlog(std::string_viewmessage, conststd::source_locationlocation=std::source_location::current()) { std::cout"info:" location.file_name()":" location.line()"" message'\n'; } intmain() { log("Helloworld!");//info:main.cpp:15Helloworld! } 原文链接:https://www.modernescpp.com/index.php/c-20-the-core-language 本文为机器之心编译,转载请联系本公众号获得授权。 ?------------------------------------------------加入机器之心(全职记者 / 实习生):hr@jiqizhixin.com投稿或寻求报道:content@jiqizhixin.com广告 & 商务合作:bd@jiqizhixin.com

上一篇:2023-11-12_GPT-4比你更会问问题:让大模型自主复述,打破与人类对话的壁垒 下一篇:2021-03-27_美国半导体简史:痴迷「降本」如何让美失去前沿优势?

TAG标签:

16
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价