
_START_ARTICLE_
C++14
_START_PARAGRAPH_
C++14是C++的现行标准的非正式名称，正式名称为"International Standard ISO/IEC 14882:2014(E) Programming Language C++"。C++14旨在作为C++11的一个小扩展，主要提供漏洞修复和小的改进。C++14标准的委员会草案（Committee Draft）N3690于2013年5月15日发表。工作草案（Working Draft）N3936已于2014年3月2日完成。最终的投票期结束于2014年8月15日，结果（一致通过）已于8月18日公布。
_START_SECTION_
新的语言特性
_START_PARAGRAPH_
以下为在C++14中被加入语言核心的特性。
_START_SECTION_
泛型的lambda
_START_PARAGRAPH_
在C++11中，lambda函数的形式参数需要被声明为具体的类型。C++14放宽了这一要求，允许lambda函数的形式参数声明中使用类型说明符auto。_NEWLINE_auto lambda = [](auto x, auto y) {return x + y;}_NEWLINE_泛型lambda函数遵循模板参数推导的规则。以上代码的作用与下面的代码相同：_NEWLINE_struct unnamed_lambda{_NEWLINE_  template<typename T, typename U>_NEWLINE_    auto operator()(T x, U y) const {return x + y;}};auto lambda = unnamed_lambda{};
_START_SECTION_
Lambda捕获部分中使用表达式
_START_PARAGRAPH_
C++11的lambda函数通过值拷贝（by copy）或引用（by reference）捕获（capture）已在外层作用域声明的变量。这意味着lambda捕获的变量不可以是move-only的类型。 C++14允许lambda成员用任意的被捕获表达式初始化。这既允许了capture by value-move，也允许了任意声明lambda的成员，而不需要外层作用域有一个具有相应名字的变量。这称为广义捕获(Generalized capture)。即在捕获子句（capture clause）中增加并初始化新的变量，该变量不需要在lambda表达式所处的闭包域（enclosing scope）中存在；即使在闭包域中存在也会被新变量覆盖(override)。新变量类型由它的初始化表达式推导。用途是可以从外层作用域中捕获只供移动的变量并使用它。_NEWLINE_这是通过使用一个初始化表达式完成的：_NEWLINE_auto lambda = [value = 1] {return value;}_NEWLINE_lambda函数lambda的返回值是1，说明value被初始化为1。被声明的捕获变量的类型会根据初始化表达式推断，推断方式与用auto声明变量相同。_NEWLINE_使用标准函数std::move可以使之被用以通过move捕获：_NEWLINE_auto ptr = std::make_unique<int>(10); //See below for std::make_uniqueauto lambda = [value = std::move(ptr)] {return *value;}
_START_SECTION_
函数返回类型推导
_START_PARAGRAPH_
C++11允许lambda函数根据return语句的表达式类型推断返回类型。C++14为一般的函数也提供了这个能力。C++14还拓展了原有的规则，使得函数体并不是{return expression;}形式的函数也可以使用返回类型推导。_NEWLINE_为了启用返回类型推导，函数声明必须将auto作为返回类型，但没有C++11的后置返回类型说明符：_NEWLINE_auto DeduceReturnType();   //返回类型由编译器推断_NEWLINE_如果函数实现中含有多个return语句，这些表达式必须可以推断为相同的类型。_NEWLINE_使用返回类型推导的函数可以前向声明，但在定义之前不可以使用。它们的定义在使用它们的翻译单元（translation unit）之中必须是可用的。_NEWLINE_这样的函数中可以存在递归，但递归调用必须在函数定义中的至少一个return语句之后：_NEWLINE_auto Correct(int i) {_NEWLINE_  if (i == 1)_NEWLINE_    return i;               // 返回类型被推断为int_NEWLINE_  else_NEWLINE_    return Correct(i-1)+i;  // 正确，可以调用}auto Wrong(int i){_NEWLINE_  if(i != 1)_NEWLINE_    return Wrong(i-1)+i;  // 不能调用，之前没有return语句_NEWLINE_  else_NEWLINE_    return i;             // 返回类型被推断为int}
_START_SECTION_
另一种类型推断
_START_PARAGRAPH_
C++11中有两种推断类型的方式。auto根据给出的表达式产生具有合适类型的变量。decltype可以计算给出的表达式的类型。但是，decltype和auto推断类型的方式是不同的。特别地，auto总是推断出非引用类型，就好像使用了std::remove_reference一样，而auto&&总是推断出引用类型。然而decltype可以根据表达式的值类别（value category）和表达式的性质推断出引用或非引用类型：_NEWLINE_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&&_NEWLINE_C++14增加了decltype(auto)的语法。允许auto的类型声明使用decltype的规则。也即，允许不必显式指定作为decltype参数的表达式，而使用decltype对于给定表达式的推断规则。_NEWLINE_decltype(auto)的语法也可以用于返回类型推导，只需用decltype(auto)代替auto。
_START_SECTION_
变量模板
_START_PARAGRAPH_
在C++之前的版本中，模板可以是函数模板或类模板（C++11引入了类型别名模板）。C++14现在也可以创建变量模板。在提案中给出的示例是变量pi，其可以被读取以获得各种类型的pi的值（例如，当被读取为整数类型时为3;当被读取为float,double,long double时，可以是近似float，double或long double精度的值）包括特化在内，通常的模板的规则都适用于变量模板的声明和定义。_NEWLINE_template<typename T>constexpr T pi = T(3.141592653589793238462643383);// 适用于特化规则:template<>constexpr const char* pi<const char*> = "pi";
_START_SECTION_
聚合类成员初始化
_START_PARAGRAPH_
C++11增加了default member initializer，如果构造函数没有初始化某个成员，并且这个成员拥有default member initializer，就会用default member initializer来初始化成员。聚合类（aggregate type）的定义被改为明确排除任何含有default member initializer的类类型，因此，如果一个类含有default member initializer，就不允许使用聚合初始化。_NEWLINE_C++14放松了这一限制，含有default member initializer的类型也允许聚合初始化。如果在定义聚合体类型的对象时，使用的花括号初始化列表没有指定该成员的值，将会用default member initializer初始化它。_NEWLINE_struct CXX14_aggregate {_NEWLINE_    int x;_NEWLINE_    int y = 42;};CXX14_aggregate a = {1}; // C++14允许。a.y被初始化为42
_START_SECTION_
二进制字面量
_START_PARAGRAPH_
C++14的数字可以用二进制形式指定。其格式使用前缀0b或0B。这样的语法也被Java、Python、Perl和D语言使用。
_START_SECTION_
数字分位符
_START_PARAGRAPH_
C++14引入单引号（'）作为数字分位符号，使得数值型的字面量可以具有更好的可读性。_NEWLINE_Ada、D语言、Java、Perl、Ruby等程序设计语言使用下划线（_）作为数字分位符号，C++之所以不和它们保持一致，是因为下划线已被用在用户自定义的字面量的语法中。_NEWLINE_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;
_START_SECTION_
deprecated 属性
_START_PARAGRAPH_
deprecated属性允许标记不推荐使用的实体，该实体仍然能合法使用，但会让用户注意到使用它是不受欢迎的，并且可能会导致在编译期间输出警告消息。 deprecated可以有一个可选的字符串文字作为参数，以解释弃用的原因和/或建议替代者。_NEWLINE_[[deprecated]] int f();[[deprecated("g() is thread-unsafe. Use h() instead")]]void g( int& x );void h( int& x );void test() {_NEWLINE_  int a = f(); // 警告：'f'已弃用_NEWLINE_  g(a); // 警告：'g'已弃用：g() is thread-unsafe. Use h() instead}
_START_SECTION_
共享的互斥体和锁
_START_PARAGRAPH_
C++14增加了一类共享的互斥体和相应的共享锁。起初选择的名字是std::shared_mutex，但由于后来增加了与std::timed_mutex相似的特性，std::shared_timed_mutex成为了更适合的名字。
_START_SECTION_
元函数的别名
_START_PARAGRAPH_
C++11定义了一组元函数，用于查询一个给定类型是否具有某种特征，或者转换给定类型的某种特征，从而得到另一个类型。后一种元函数通过成员类型type来返回转换后的类型，当它们用在模板中时，必须使用typename关键字，这会增加代码的长度。_NEWLINE_template <class T>type_object<_NEWLINE_  typename std::remove_cv<_NEWLINE_    typename std::remove_reference<T>::type_NEWLINE_  >::type>get_type_object(T&);_NEWLINE_利用类型别名模板，C++14提供了更便捷的写法。其命名规则是：如果标准库的某个类模板（假设为std::some_class）只含有唯一的成员，即成员类型type，那么标准库提供std::some_class_t<T>作为typename std::some_class::type的别名。_NEWLINE_在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。_NEWLINE_template <class T>type_object<std::remove_cv_t<std::remove_reference_t<T>>>get_type_object(T&);
_START_SECTION_
关联容器中的异构查找
_START_PARAGRAPH_
C++标准库定义了四个关联容器类。set和multiset允许用户根据一个值在容器中查找对应的的同类型的值。map和multimap容器允许用户指定键（key）和值（value）的类型，根据键进行查找并返回对应的值。然而，查找只能接受指定类型的参数，在map和multimap中是键的类型，而在set和multiset容器中就是值本身的类型。_NEWLINE_C++14允许通过其他类型进行查找，只需要这个类型和实际的键类型之间可以进行比较操作。这允许std::set<std::string>使用const char*，或任何可以通过operator< 与std::string比较的类型作为查找的参数。_NEWLINE_为保证向后兼容性，这种异构查找只在提供给关联容器的比较器允许的情况下有效。标准库的泛型比较器，如std::less<>与std::greater<>允许异构查找。
_START_SECTION_
通过类型寻址多元组
_START_PARAGRAPH_
C++11引入的std::tuple类型允许不同类型的值的聚合体用编译期整型常数索引。C++14还允许使用类型代替常数索引，从多元组中获取对象。若多元组含有多于一个这个类型的对象，将会产生一个编译错误：_NEWLINE_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
_START_SECTION_
较小的标准库特性
_START_PARAGRAPH_
std::make_unique可以像std::make_shared一样使用，用于产生std::unique_ptr对象。_NEWLINE_std::is_final，用于识别一个class类型是否禁止被继承。_NEWLINE_std::integral_constant增加了一个返回常量值的operator()。_NEWLINE_全局std::begin/std::end函数之外，增加了std::cbegin/std::cend函数，它们总是返回常量迭代器（constant iterators）。
_START_SECTION_
已被移除或是不包含在C++14标准的特性
_START_PARAGRAPH_
因为C++14的主要目的是漏洞修复和小的改进，一些重量级的特性被从C++14中移除，其中有部分将加入C++17标准。
_START_SECTION_
关于数组的扩展
_START_PARAGRAPH_
在C++11和之前的标准中，在堆栈上分配的数组被限制为拥有一个固定的、编译期确定的长度。这一扩展允许在堆栈上分配的一个数组的最后一维具有运行期确定的长度。_NEWLINE_运行期确定长度的数组不可以作为对象的一部分，也不可以具有全局存储期，他们只能被声明为局部变量。运行期确定长度的数组也可以使用C++11的基于范围的for循环。_NEWLINE_同时还将添加std::dynarray类型，它拥有与std::vector和std::array相似的接口。代表一个固定长度的数组，其大小在运行期构造对象时确定。std::dynarray类被明显地设计为当它被放置在栈上时（直接放置在栈上，或作为另一个栈对象的成员），可以使用栈内存而不是堆内存。_NEWLINE_由于一些设计无法达成一致，这一扩展已被放弃。
_START_SECTION_
Optional值
_START_PARAGRAPH_
类似于C#中的可空类型，optional类型可能含有或不含有一个值。这一类型基于Boost的boost::optional类，而添加了C++11和C++14中的新特性，诸如移动和in-place构造。它不允许用在引用类型上。这个类被专门的设计为一个literal type（如果模板参数本身是一个literal type），因此，它在必要的情况下含有constexpr构造函数。
_START_SECTION_
Concepts Lite
_START_PARAGRAPH_
被C++11拒绝后，Concepts受到彻底的修改。Concepts Lite是Concepts的一个部分，仅包含类型约束，而不含concept_map和axiom。 ISO/IEC TS 19217:2015 Information technology -- Programming languages -- C++ Extensions for concepts已出版。