C++14新特性

C++14C++的现行标准的非正式名称,正式名称为"International Standard ISO/IEC 14882:2014(E) Programming Language C++"。C++14旨在作为C++11的一个小扩展,主要提供漏洞修复和小的改进。C++14标准的委员会草案(Committee Draft)N3690于2013年5月15日发表。[1]工作草案(Working Draft)N3936已于2014年03月02日完成。最终的投票期结束于2014年8月15日,结果(一致通过)已于8月18日公布。[2]

目录

新的语言特性

以下为在C++14中被加入语言核心的特性。

泛型的lambda

在C++11中,lambda函数的形式参数需要被声明为具体的类型。C++14放宽了这一要求,允许lambda函数的形式参数声明中使用类型说明符auto[3]

auto lambda = [](auto x, auto y) {return x + y;}

泛型lambda函数遵循模板参数推导的规则。以上代码的作用与下面的代码相同:[4]

struct unnamed_lambda{
  template<typename T, typename U>
    auto operator()(T x, U y) const {return x + y;}};auto lambda = unnamed_lambda();

Lambda捕获部分中使用表达式

C++11的lambda函数通过值拷贝(by copy)或引用(by reference)捕获(capture)已在外层作用域声明的变量。这意味着lambda的值成员不可以是move-only的类型。[5] C++14允许被捕获的成员用任意的表达式初始化。这既允许了capture by value-move,也允许了任意声明lambda的成员,而不需要外层作用域有一个具有相应名字的变量。[6]

这是通过使用一个初始化表达式完成的:

auto lambda = [value = 1] {return value;}

lambda函数lambda的返回值是1,说明value被初始化为1。被声明的捕获变量的类型会根据初始化表达式推断,推断方式与用auto声明变量相同。

使用标准函数std::move可以使之被用以通过move捕获:

auto ptr = std::make_unique<int>(10); //See below for std::make_uniqueauto lambda = [ptr = std::move(ptr)] {return *ptr;}

声明ptr = std::move(ptr)使用了两次ptr。第一次使用声明了一个新的变量,但在捕获部分,这个变量还不在作用域内。所以第二个ptr表示之前在lambda之外声明的变量。[7]

函数返回类型推导

C++11允许lambda函数根据return语句的表达式类型推断返回类型。C++14为一般的函数也提供了这个能力。C++14还拓展了原有的规则,使得函数体并不是{return ;}形式的函数也可以使用返回类型推导。[8]

为了启用返回类型推导,函数声明必须将auto作为返回类型,但没有C++11的后置返回类型说明符:

auto DeduceReturnType();   //返回类型由编译器推断

如果函数实现中含有多个return语句,这些表达式必须可以推断为相同的类型。[9]

使用返回类型推导的函数可以前向声明,但在定义之前不可以使用。它们的定义在使用它们的翻译单元(translation unit)之中必须是可用的。

这样的函数中可以存在递归,但递归调用必须在函数定义中的至少一个return语句之后:[9]

auto Correct(int i) {
  if (i == 1)
    return i;               // 返回类型被推断为int
  else
    return Correct(i-1)+i;  // 正确,可以调用}auto Wrong(int i){
  if(i != 1)
    return Wrong(i-1)+i;  // 不能调用,之前没有return语句
  else
    return i;             // 返回类型被推断为int}

另一种类型推断

C++11中有两种推断类型的方式。auto根据给出的表达式产生具有合适类型的变量。decltype可以计算给出的表达式的类型。但是,decltypeauto推断类型的方式是不同的。特别地,auto总是推断出非引用类型,就好像使用了std::remove_reference一样,而auto&&总是推断出引用类型。然而decltype可以根据表达式的值类别(value category)和表达式的性质推断出引用或非引用类型:[8]

int i;int&& f();auto x3a = i;              // x3a的类型是intdecltype(i) x3d = i;       // x3d的类型是intauto x4a = (i);            // x4a的类型是intdecltype((i)) x4d = (i);   // x4d的类型是int&auto x5a = f();            // x5a的类型是intdecltype(f()) x5d = f();   // x5d的类型是int&&

C++14增加了decltype(auto)的语法。这允许不必显式指定作为decltype参数的表达式,而使用decltype对于给定表达式的推断规则。

decltype(auto)的语法也可以用于返回类型推导,只需用decltype(auto)代替auto[9]

放松的constexpr限制

C++11引入了声明为constexpr的函数的概念。声明为constexpr函数的意义是:如果其参数均为合适的编译期常量,则对这个constexpr函数的调用就可用于期望常量表达式的场合(如模板的非类型参数,或枚举常量的值)。如果参数的值在运行期才能确定,或者虽然参数的值是编译期常量,但不符合这个函数的要求,则对这个函数调用的求值只能在运行期进行。然而C++11要求constexpr函数只含有一个将被返回的表达式(也可以还含有static_assert声明等其它语句,但允许的语句类型很少)。

C++14将放松这些限制。声明为constexpr的函数可以含有以下内容:[8]

  • 任何声明,除了:

    • staticthread_local变量。

    • 没有初始化的变量声明。

  • 条件分支语句ifswitch

  • 所有的循环语句,包括基于范围的for循环。

  • 表达式可以改变一个对象的值,只需该对象的生命期在声明为constexpr的函数内部开始。包括对有constexpr声明的任何非const非静态成员函数的调用。

goto仍然不允许在constexpr函数中出现。

此外,C++11指出,所有被声明为constexpr的非静态成员函数也隐含声明为const(即函数不能修改*this的值)。这点已经被删除,非静态成员函数可以为非const[10]

变量模板

C++之前的版本中,模板可以是函数模板或类模板(C++11引入了类型别名模板)。C++14现在也可以创建变量模板。包括特化在内,通常的模板的规则都适用于变量模板的声明和定义。[6][11]

聚合体成员初始化

C++11新增member initializer,这是一个表达式,被应用到类作用域的成员上,如果构造函数没有初始化这个成员。聚合体的定义被改为明确排除任何含有member initializer的类,因此,他们不允许使用聚合初始化。

C++14将放松这一限制,[8]这种类型也允许聚合初始化。如果花括号初始化列表不提供该参数的值,member initializer会初始化它。[12]

二进制字面量

C++14的数字可以用二进制形式指定。[8]其格式使用前缀0b0B。这样的语法也被JavaPythonPerlD语言使用。

数字分位符

C++14引入单引号(')作为数字分位符号,使得数值型的字面量可以具有更好的可读性。[13]

AdaD语言JavaPerlRuby等程序设计语言使用下划线(_)作为数字分位符号,C++之所以不和它们保持一致,是因为下划线已被用在用户自定义的字面量的语法中。

auto integer_literal = 100'0000;auto floating_point_literal = 1.797'693'134'862'315'7E+308;auto binary_literal = 0b0100'1100'0110;auto silly_example = 1'0'0'000'00;

新的标准库特性

共享的互斥体和锁

C++14增加了一类共享的互斥体和相应的共享锁[14][15]。起初选择的名字是std::shared_mutex,但由于后来增加了与std::timed_mutex相似的特性,std::shared_timed_mutex成为了更适合的名字。[16]

元函数的别名

C++11定义了一组元函数,用于查询一个给定类型是否具有某种特征,或者转换给定类型的某种特征,从而得到另一个类型。后一种元函数通过成员类型type来返回转换后的类型,当它们用在模板中时,必须使用typename关键字,这会增加代码的长度。

template <class T>type_object<
  typename std::remove_cv<
    typename std::remove_reference<T>::type
  >::type>get_type_object(T&);

利用类型别名模板,C++14提供了更便捷的写法。其命名规则是:如果标准库的某个类模板(假设为std::some_class)只含有唯一的成员,即成员类型type,那么标准库提供std::some_class_t<T>作为typename std::some_class::type的别名。

在C++14,拥有类型别名的元函数包括:remove_const、remove_volatile、remove_cv、add_const、add_volatile、add_cv、remove_reference、add_lvalue_reference、add_rvalue_reference、make_signed、make_unsigned、remove_extent、remove_all_extents、remove_pointer、add_pointer、aligned_storage、aligned_union、decay、 enable_if、conditional、common_type、underlying_type、result_of、tuple_element。

template <class T>type_object<std::remove_cv_t<std::remove_reference_t<T>>>get_type_object(T&);

关联容器中的异构查找

C++标准库定义了四个关联容器类。set和multiset允许用户根据一个值在容器中查找对应的的同类型的值。map和multimap容器允许用户指定键(key)和值(value)的类型,根据键进行查找并返回对应的值。然而,查找只能接受指定类型的参数,在map和multimap中是键的类型,而在set和multiset容器中就是值本身的类型。

C++14允许通过其他类型进行查找,只需要这个类型和实际的键类型之间可以进行比较操作。[17]这允许std::set<std::string>使用const char*,或任何可以通过operator< 与std::string比较的类型作为查找的参数。

为保证向后兼容性,这种异构查找只在提供给关联容器的比较器允许的情况下有效。标准库的泛型比较器,如std::less<>std::greater<>允许异构查找。[18]

标准自定义字面量

C++11增加了自定义字面量(user-defined literals)的特性,使用户能够定义新的字面量后缀,但标准库并没有对这一特性加以利用。C++14标准库定义了以下字面量后缀:[17]

  • "s",用于创建各种std::basic_string类型。

  • "h"、"min"、"s"、"ms"、"us"、"ns",用于创建相应的std::chrono::duration时间间隔。

using namespace std::literals;std::string str = "hello world"s;std::chrono::seconds dur = 60s;

两个"s"互不干扰,因为表示字符串的只能对字符串字面量操作,而表示秒的只针对数字。[19]

通过类型寻址多元组

C++11引入的std::tuple类型允许不同类型的值的聚合体用编译期整型常数索引。C++14还允许使用类型代替常数索引,从多元组中获取对象。[17]若多元组含有多于一个这个类型的对象,将会产生一个编译错误:[20]

tuple<string, string, int> t("foo", "bar", 7);int i = get<int>(t);        // i == 7int j = get<2>(t);          // Same as before: j == 7string s = get<string>(t);  //Compiler error due to ambiguity

较小的标准库特性

std::make_unique可以像std::make_shared一样使用,用于产生std::unique_ptr对象。[6]

std::is_final,用于识别一个class类型是否禁止被继承

std::integral_constant增加了一个返回常量值的operator()[17]

全局std::begin/std::end函数之外,增加了std::cbegin/std::cend函数,它们总是返回常量迭代器(constant iterators)。

已被移除或是不包含在C++14标准的特性

因为C++14的主要目的是漏洞修复和小的改进,一些重量级的特性被从C++14中移除,而移入各自的Technical Specification,并有可能合并入未来的C++17标准。

关于数组的扩展

以下特性将由Technical Specification—Array Extensions提供支持。[21]

C++11和之前的标准中,在堆栈上分配的数组被限制为拥有一个固定的、编译期确定的长度。这一扩展允许在堆栈上分配的一个数组的最后一维具有运行期确定的长度。[6]

运行期确定长度的数组不可以作为对象的一部分,也不可以具有全局存储期,他们只能被声明为局部变量。运行期确定长度的数组也可以使用C++11的基于范围的for循环。[22]

同时还将添加std::dynarray类型,它拥有与std::vectorstd::array相似的接口。代表一个固定长度的数组,其大小在运行期构造对象时确定。std::dynarray类被明显地设计为当它被放置在栈上时(直接放置在栈上,或作为另一个栈对象的成员),可以使用栈内存而不是堆内存。

Optional值

以下特性将由C++ Extensions for Library Fundamentals提供支持。[23]

类似于C#中的可空类型,optional类型可能含有或不含有一个值。这一类型基于Boostboost::optional类,而添加了C++11和C++14中的新特性,诸如移动和in-place构造。它不允许用在引用类型上。这个类被专门的设计为一个literal type(如果模板参数本身是一个literal type),因此,它在必要的情况下含有constexpr构造函数。[24]

Concepts Lite

参见: 概念 (C++)

被C++11拒绝后,Concepts受到彻底的修改。Concepts Lite是Concepts的一个部分,仅包含类型约束,而不含concept_mapaxiom[25]。它将在一个单独的Technical Specification中发展,并有可能加入C++17。

(0)

相关推荐

  • 他来了,他来了,C 17新特性精华都在这了

    程序喵之前已经介绍过C++11的新特性和C++14的新特性(点击对应文字,直接访问),今天向亲爱的读者们介绍下C++17的新特性,现在基本上各个编译器对C++17都已经提供完备的支持,建议大家编程中尝 ...

  • 理解lambda表达式,为什么用它?

    初学者接触 lambda表达式 ,觉得语法很清奇,正好今天看到 python weekly 推送了一个youtube的视频教程,今天大邓就顺便领大家简单认识一下lambda语法. up主:PyLeni ...

  • C++11/14的新特性

    新的字符串表示方式--原生字符串(Raw String Literals) C/C++中提供了字符串,字符串的转义序列,给输出带来了很多不变,如果需要原生义的时候,需要反转义,比较麻烦. C++提供了 ...

  • iOS 14发布在即,三分钟快速提前了解新特性!

    明美无限 果粉关注不迷路! 文|明美无限 相信有持续关注明美无限至今的果粉们应该都知道了,一年一度的苹果公司全球开发者大会马上就到了,但今年注定是特殊的一年,苹果公司将首次举行线上模式的WWDC 20 ...

  • 苹果iOS 14前瞻:这些新特性还是值得期待的!

    明美无限 果粉关注不迷路! 文|明美无限 时至今日,广大的果粉们应该都明了了,苹果的iPhone手机之所以能受到大量用户的喜欢,跟iPhone手机使用的iOS系统有很大的关系. 相信有持续关注明美无限 ...

  • iOS 14被曝新特性:果粉呼声最高的功能要来!

    明美无限 果粉关注不迷路! 文|明美无限 相信有一直关注明美无限的果粉们应该都清楚,在手机行业,苹果一直以"老大哥"的身份存在,主要有两点利器支撑.一是先进的A系列芯片,二是iOS ...

  • iOS 14被曝新特性:苹果终于被妥协了!

    明美无限 果粉关注不迷路! 文|明美无限 当时间流转到现如今,相信有一直关注明美无限至今的果粉们应该都清楚,在iPhone 11系列上市后,iOS系统的升级也迎来了爆发式的增长,但被不断爆出的iOS ...

  • cad2022好用吗?cad2022新特性 AutoCAD LT 2022 for Mac最新版

    AutoCAD2022中文版是Autodesk公司的一款专业CAD绘图软件,aAutoCAD mac版可用于建筑设计.机械设计.电气设计.工程制图等各种行业! 全新功能 探索AutoCADLT®202 ...

  • golang1.16新特性速览

    今天是假期最后一天,明天起大家也要陆续复工了.golang1.16也在今天正式发布了. 原定计划是2月1号年前发布的,不过迟到也是golang的老传统了,正好也趁着最后的假期快速预览一下golang1 ...

  • Oracle 19.8新特性"asmcmd credverify" and "asmcmd credfix"

    平台:Redhat Linux 7.6 数据库版本:Oracle 19.10 问题描述:进行OCR磁盘替换DD破坏实验,并删除原有的OCR磁盘组.中间过程中,因spfile文件以及asm密码文件没有进 ...

  • 安卓12重磅新特性曝光:国产流氓APP将被彻底终结?

    不同于早些年,现在的智能手机系统基本上除了苹果的iOS,就是安卓了.安卓系统从第一代走到今天已经来到了第十二个版本,相比早期的安卓系统,现在的安卓系统越来越完善,在流畅度和安全性上也越发看齐苹果iOS ...