关于C++14:你需要知道的新特性
2018-01-24 00:27
323 查看
使C++更加安全和更加方便的有用新特性
今年8月,经过投票, C++14标准获得一致通过。目前唯一剩下的工作是ISO进行C++标准的正式发布。在本文中,我关注的是新标准中的几个重要点,展示了即将到来的改变会如何影响你的编程方式,特别是在使用被现代C++称之为习语和范型的特性时。C++标准委员会决心使标准制定过程比过去10年更加快速。这意味着,距上一个标准(即C++11)仅3年的C++14是一次相对较小的发布。这远非一个令人失望的消息,恰恰相反,这对程序员来说是个好消息。因为这样的话,开发人员能够实时地跟上新特性。所以,今天你就可以开始使用C++14的新特性了—而且,如果你的工具链足够灵活的话,你几乎可以使用全部新特性了。
目前你可以从这里得到标准草案的一份免费副本。遗憾的是,当最终版本的标准发布时,ISO会进行收费。
缩短标准发布的时间间隔可以帮助编译器作者更实时地跟上语言变化。仅隔三年就再次发布,需要调整以适应的变化也就更少。
本文的例子主要在clang 3.4上测试过,clang 3.4覆盖了大多数C++14的新特性。目前,g++对新特性的覆盖更少一些,而Visual
C++似乎落后更多。
C++14:重大变化
接下来,本文将说明对程序员编码工作会有重大影响的C++14特性,在给出实例的同时,还讨论了何时何地因何使用这些特性。
返回类型推导
在这次发布中,关键字auto的作用扩大了。C++语言本身仍然是类型安全的,但是类型安全的机制逐渐改由编译器而不是程序员来实现。在C++11中,程序员最初使用auto是用于声明。这对于像迭代器的创建之类尤其有用,因为完整的正确的类型名可能长得可怕。使用了auto的C++代码则易读得多:
任何有过大型项目工作经验的C++程序员都应该很熟悉这个问题–对单一数据结构的修改可能引起代码库看似无穷无尽的迭代:修改变量,修改参数,修改返回类型。auto的增加使用对减少这种工作贡献不小。
注意在上述例子及本文的余下部分,我创建并使用有名的lambda。我猜想,大多数用户在std::find_if()这样的函数中都是把lambda定义为匿名的内联对象的,这确实是非常方便的方式。由于浏览器的页面宽度有限,我认为把lambda的定义和使用分开能够使读者通过浏览器阅读代码比较容易。因此,这并不是各位读者一定应该仿效的方式,读者们只是应该感激这样使代码更加易读–特别是,当你是一位缺乏lambda使用经验的读者时。
说回auto,使用auto作为返回类型带来的一个直接推论是其分身decltype(auto)的实现,以及它在类型推导时将遵循的规则。像下面的代码片段展示的一样,现在你可以使用它自动地捕获类型信息:
泛型Lambdas
auto悄悄潜伏的另一个地方是lambda参数的定义。使用auto类型声明来定义lambda参数等价于放松限制地创建模板函数。基于推导出的参数类型,lambda将进行特定的实例化。这方便了可重用于不同上下文的lambda的创建。在下文的简单例子中,我创建了一个lambda,用来作为一个标准库函数的谓词函数。在C++11中,我需要明确地实例化一个lambda用于整数的相加,再实例化另一个lambda用于字符串的相加。
有了泛型lambda后,我可以只定义一个带有泛型参数的lambda。尽管泛型lambda在语法上没有包含关键字template,但是很显然,它仍是C++泛型编程的进一步延展。
可初始化的Lambda捕获
在C++11中,我们不得不开始适应lambda capture这一概念。其声明指导编译器进行closure的创建:closure是一个由lambda定义的函数的实例,同时,它绑定了定义于lambda作用域之外的变量。在上文有关推导返回类型的示例中,定义了一个lambda,它捕获变量name,该变量被作为一个搜索字符串的谓词函数的源:
这一切都OK,但同时也带来了一些限制。我认为,C++标准委员会觉得需要特别强调的一点是,不能使用move-only语法来初始化捕获的变量。
这说明什么呢?如果我们想把lambda作为一个参数的sink(接收器),我们会使用move语法来捕获其作用域之外的变量。作为一个例子,考虑一下如何得到一个lambda,它接收具有move-only特点的unique_ptr对象。首先,尝试通过值捕获将以失败告终:
修改代码通过引用捕获p能够编译通过,但是这并不能达到期望的效果,我们的初衷是通过移动变量的值到本地拷贝来接收变量值。最终,创建一个局部变量并在通过引用捕获时调用std::move()能够达到目的,但是其效率略低。
修改捕获子句的语法可以解决效率低的问题。现在,不仅仅可以声明一个捕获变量,还可以进行初始化。作为标准中的一个例子,简单情形下的使用看起来像这样:
[[deprecated]]属性
当我第一次在Java中见到deprecated属性的使用时,我承认我有点嫉妒这门语言。对大多数程序员来说,代码陈旧是个大问题。(有因删除代码而被称赞过吗?反正我从来没有。)这个新属性提供了解决这个问题的系统方法。它的用法方便又简单—只需要把[[deprecated]]标签放到声明的前面即可—可以是类,变量,函数,或者其他一些实体的声明。结果看起来像这样:
这个标签具有包括消息参数的另一种形式。同样地,如何处理该消息取决于开发人员。显然,clang3.4直接忽略了该消息。因为,如下代码片段的输出中并不包含错误消息:
二进制常量和单引号用作数字分位符
这两个新特性并不惊天动地,但它们确实代表了好的语法改进。语言中像这样的持续小改进可以提高代码的可读性并因此而减少bug数量。除了原有的十进制、十六进制和比较不常用的八进制表示方法之外,C++程序员现在还可以使用二进制表示常量了。二进制常量以前缀0b(或0B)开头,二进制数字紧随其后。
在英美两国,在写数字时,我们习惯于使用逗号作为数字的分隔符,如:$1,000,000。这些数字分隔符纯为方便读者,它提供的语法线索使我们的大脑在处理长串的数字时更加容易。
基于完全相同的原因,C++标准委员会为C++语言增加了数字分隔符。数字分隔符不会影响数字的值,它们的存在仅仅是为了通过分组使数字的读写更容易。
使用哪个字符来表示数字分隔符呢?在C++中,几乎每个标点字符都已经有特定的用途了,因此并没有明显的选择。最终的结果是使用单引号字符,这使得百万美元在C++中写作1’000’000.00。记住,分隔符不会对常量的值有任何影响,因此,1’0’00’0’00.00也是表示百万。
下面是一个结合了这两种新特性的例子:
其他
C++14规范中的其他特性并不需要如此多的阐释。变量模板就是将模板扩展到变量。用滥了的例子是变量模板pi<T>的实现。当T表示double类型时,变量返回3.14。表示int类型时,返回3。表示std::string类型时,则可能返回字符串”3.14”或者”pi”。当<limits>头文件写好的时候,这将是一个很好的特性。
变量模板的语法及语义与类模板几乎是相同的,所以,即使不进行任何额外的学习,使用它们也应该是没有问题的(如果你已经了解了类模板的话)。
constexpr函数的限制被放松了。现在允许在case语句,if语句,循环语句等语句中进行多处返回了。这扩展了可在编译期间完成的事情的范围,增加可在编译期间完成的事情这一趋势在模板被引入后发展得尤其迅速。
其他的小特性包括可指定大小的资源回收函数和一些语法整理。
接下来
C++标准委员会明显感受到了压力,正在通过改进来保持C++语言与时俱进。在这个十年期中,他们已经在至少一个(即C++17)以上的标准上进行努力了。也许更有趣的是,几个衍生组织的创立,这些组织可以创建技术规范文档。这些文档不会提升为标准,但是它们会发表并获得ISO标准委员会的认可。根据推测,这些事务将以更快的速度得到推进。这些组织当前工作的八大领域包括以下方面:
文件系统
并发性
并行性
网络
C++的AI概念(Artificial Intelligence,人工智能)–一直处于规范中。
这些技术规范的成功与否取决于其是否被采纳和使用。如果我们发现所有开发人员都跟随它们,那么这种进行标准化的新途径就算成功了。
这些年来C/C++发展良好。现代C++(或许以C++11作为开始)在保持性能的同时,在使C++语言更加易用更加安全方面取得了引人注目的进展。对于某些类型的工作,你很难找出C/C++之外的任何合理替代品。C++14并未做出C++11版本中那样的大改进,但是它把语言保持在一条很好的路上。如果C++标准委员会在未来十年保持其目前的效率,那么C++应该能够继续作为当性能被定为目标时的首选语言。
相关文章推荐
- 关于C++14:你需要知道的新特性
- 关于C++14:你需要知道的新特性
- 转:关于C++14:你需要知道的新特性
- 关于Android的.so文件所需要知道的
- 【脚本语言系列】关于Python设计模式,你需要知道的事情
- 关于CPU Cache:程序猿需要知道的那些
- 关于Android Service真正的完全详解,你需要知道的一切
- 关于 PHP 5.4 你所需要知道的
- 关于字符编码,你所需要知道的(ASCII,Unicode,Utf-8,GB2312…)
- 关于 Linux 进程你所需要知道的一切
- 关于MongoDB你需要知道的几件事
- 关于Spring MVC 4,你需要知道的那些事
- Java并发——关于Java内存模型(JMM),你需要知道什么?
- [译]关于iOS和OS X废弃的API你需要知道的一切
- 关于字符编码,你所需要知道的(转)
- 关于service需要知道的一切
- 【脚本语言系列】关于Python数据库访问ActiveXDataObject,你需要知道的事
- 关于Android的.so文件你所需要知道的
- Linux内核:关于中断你需要知道的
- 关于HTML语法规则你需要知道的