C++17 相比于 C++14 的所有重大变化

摘要

本文档列举了自C++14发布以来,到C++17 DIS(N4660)发布为止,应用于C++工作草案(working draft)的所有重大变化。重大变化(major changes)是以专门的文件(paper)的形式加入的。不是每个文件都单独在此提及,没有单独提及的文件在下面简要列出。CWG或LWG问题清单(issue list)中的问题解决方案(issue resolution)通常不包括在重大变化之内,但是包含问题解决方案的文件也会简要列出。

目录

  1. 删除或弃用的特性
  2. 具有全局影响的新的核心语言特性
  3. 具有局部影响的新的核心语言特性
  4. 新的库特性
  5. 对现有特性的修改
  6. 杂项
  7. 未列入的文件
  8. 展示C++17的代码片段合集

删除或弃用的特性

文件:N4086
概要:删除trigraph
注释:字符序列 ??! 不再表示 | 。实现(implementation)可以把类似trigraph的功能作为输入编码的一环。

文件:P0001R1
概要:删除register
注释:register仍然是保留字,但是不再具有任何语义。

文件:P0002R1
概要:删除bool类型的++运算
注释:前自增和后自增运算符不再接受bool类型的操作数。

文件:P0003R5
概要:删除throw(A, B, C)
注释:形如throw(A, B, C)的动态异常规范(dynamic exception specification)不再是合法的。throw()保留,成为noexcept(true)的同义词。注意throw()的语义变化。

文件:P0386R2
概要:弃用static constexpr成员的重复声明
注释: 对于struct X { static constexpr int n = 10; };,int X::n;不再是定义,而是多余的重复声明,这种重复声明已被弃用。成员X::n是隐含的inline变量(见下文)。

———-

文件:N4190
概要:删除auto_ptr、random_shuffle、<functional>中的过时部分
注释:在C++11已经被弃用并被更好的组件取代的功能将不再包含于C++17中。它们的名字仍然是保留的,实现可以选择继续提供。

文件:P0004R1
概要:删除被弃用的iostream成员
注释:同上

文件:P0302R1
概要:删除std::function的内存分配器(allocator)支持
注释:多态函数包装器function不再具有接受内存分配器的构造函数。内存分配器支持对具有类型擦除(type-erase)功能的可复制类型来说很困难,可能无法有效实现。

文件:P0063R3(见下文)
概要:弃用一些C库(C library)头文件(header)
注释:“C库”(C library,这个术语指的是C++标准库的一部分, 而不是C标准库的一部分)中的以下头文件被弃用:<ccomplex>、<cstdalign>、<cstdbool>、<ctgmath>。注意<ciso646>头文件没有被弃用。

文件:P0174R2
概要:弃用标准库中的陈旧部分
注释:以下组件被弃用:allocator<void>、raw_storage_iterator、get_temporary_buffer、is_literal_type、std::iterator。

文件:P0618R0
概要:弃用<codecvt>
注释:整个<codecvt>头文件(注意codecvt类并不在这个头文件中)被弃用。wstring_convert和wbuffer_convert也被弃用。这些功能难以正确使用,甚至有怀疑它们的规范是否正确。用户应该使用专用的文本处理库。

文件:P0371R1
概要:暂时弃用memory_order_consume
注释: 当前的“consume”内存序的语义被发现是不够的,需要重新定义。这项工作希望能在C++的下一版中完成。在进行这项工作的时间里,建议用户不要使用“consume”内存序,而是使用“acquire”内存序,以免将来遇到问题。

文件:P0521R0
概要:弃用shared_ptr::unique
注释:该成员函数暗示了没有实际提供的行为。

文件:P0604R0
概要:弃用result_of
注释:请改用新的trait:invoke_result。

具有全局影响的新的核心语言特性

这些是在不需要你知情或同意的情况下,你可能遇到的特性。

文件:P0012R1
概要:异常规范(exception specification)作为类型系统的一部分
注释:函数的异常规范现在是函数类型的一部分:void f() noexcept(true); 和 void f() noexcept(false); 是具有不同类型的函数。函数指针可以按符合常理的方式转换。(但是这两个函数 f 不能构成重载。)这个变化加强了类型系统。例如,API可以通过类型系统要求回调函数不抛出异常。

文件:P0135R1
概要:保证的复制消除(guaranteed copy elision)
注释:prvalue和glvalue的含义已被修改,prvalue不再代表对象(object),而仅仅代表“初始化”(“initialization”)。返回prvalue的函数不再会复制对象(强制复制消除“mandatory copy elision”),并且有了新的从prvalue到glvalue的转换,叫做temporary materialization conversion。这个变化意味着复制消除是保证了的,而且甚至可以应用于不可移动或复制的类型。这允许你定义返回这种(不可移动或复制的)类型的函数。

文件:P0035R4
概要:过度对齐类型(over-aligned types——即alignment超过std::max_align_t的类型)的动态内存分配
注释:动态内存分配(operator new)现在可以支持过度对齐的类型,这个运算符的一个新的重载接受对齐要求(alignment)参数。仍然是由实现决定支持哪些对齐。

文件:P0145R3
概要:更严格的表达式求值顺序
注释:对某些子表达式的求值顺序的规定更多了。这个变化的一个重要方面是函数的各个实参现在以不确定(indeterminate)的顺序的求值(也就是说没有交错 interleaving),而以前只是未指定的(unspecified)。注意重载运算符的求值顺序和调用方式有关:如果按照运算符的形式调用,就和相应的内置运算符的顺序相同;如果按照函数调用的形式调用,就和一般的函数调用相同(也就是不确定的 indeterminate)。

具有局部影响的新的核心语言特性

这些是如果你要使用,你就需要知道的特性。

文件:N4267
概要:u8字符字面量
注释:具有u8前缀的字符字面量产生一个在UTF-8中占有一个编码单元(code unit)的合法Unicode代码点(code point)对应的字符,换句话说,就是产生一个ASCII值。例如:u8’x’。

文件:P0245R1
概要:十六进制浮点数字面量
注释:具有十六进制底数和十进制指数的浮点数字面量: 0xC.68p+2, 0x1.P-126。C语言自从C99开始就支持这种语法, printf的%a可以输出这种形式的浮点数。

文件:N4295, P0036R0
概要:fold表达式
注释:用于迭代地将二元运算符应用于参数包(parameter pack)的元素的便利语法:template <typename …Args> auto f(Args …args) { return (0 + … + args); }

文件:P0127R2
概要:template <auto>
注释:模板的非类型形参可以用占位符类型auto声明。例如:
• template <auto X> struct constant { static constexpr auto value = X; };
• Delegate<&MyClass::some_function>
(←_←第二个例子的完整版本见下文)

文件:P0091R3, P0512R0, P0433R2, P0620R0
概要:类模板参数推导
注释:类模板的模板参数现在可以从构造函数推导。例如 pair p(1, ‘x’); 定义 p 为 pair<int, char> 类型的变量(这不是HTML错误,模板实参是故意省略的)。显式的推导指引(deduction guide)是隐式推导的补充,显式的推导指引允许作者定制推导如何发生,或者禁止推导。

文件:P0292R2
概要:Constexpr if
注释:新的 if constexpr (condition) 语句根据常量表达式(constant expression)的值选择执行哪个分支。在模板的实例中,只有在条件(condition)具有合适的值的时候,对应的分支才会实例化。

文件:P0305R1
概要:带初始化的选择语句
注释:选择语句 if 和 switch 有了一个新的、可选的初始化部分:if (auto it = m.find(key); it != m.end()) return it->second;

文件:P0170R1
概要:Constexpr lambda
注释:lambda表达式现在可以是常量表达式了:auto add = [](int a, int b) constexpr { return a + b; }; int arr[add(1, 2)];

文件:P0018R3
概要:lambda捕获*this
注释:以前:[self = *this]{ self.f(); } 现在:[*this]{ f(); }

文件:P0386R2, P0607R0
概要:inline变量
注释:在头文件中:inline int n = 10; 所有定义都指代同一个实体。static constexpr 成员变量隐含地成为 inline 变量。(标准库中的常量,不论是已有的还是新增的,都已使用inline。)

文件:P0217R3, P0615R0
概要:结构化绑定
注释:auto [it, ins] = m.try_emplace(key, a1, a2, a3);
可以分解数组、所有成员都是public的类、像pair、tuple和array一样遵循get<N>协议的自定义类型。

文件:P0061R1
概要:__has_include
注释:检查能否包含特定头文件的预处理运算符。

文件:P0188R1 P0189R1 P0212R1
概要:属性(attribute)[[fallthrough]]、[[nodiscard]]、[[maybe_unused]](分别对应三个文件)
注释:一套新的标准化属性。属性没有必要的语义,但是鼓励实现发出或抑制适当的诊断(警告)。

文件:P0137R1
概要:launder
注释:语言支持工具(“优化屏障optimisation barrier”),允许库重新使用存储(storage),并通过旧指针访问该存储(以前是不允许的)。(这是实现者的专家工具,预期不会在“正常”代码中出现)。

文件:P0298R3
概要:字节类型
注释:新的类型byte在<cstddef>中定义(不在<stddef.h>,并且只定义在命名空间std中),它和unsigned char具有相同的布局,和现有的字符类型一样允许别名(aliasing),并且定义了按位操作。

新的库特性

文件:P0226R1
概要:数学特殊函数(mathematical special functions)
注释:前国际标准ISO/IEC 29124:2010(数学特殊函数)的内容现在是C++的一部分。 这些函数只添加到<cmath> ,而没有添加到<math.h> ,并且只定义在命名空间std中。

文件:P0218R0, P0219R1, P0317R1, P0392R0, P0430R2, P0492R2
概要:文件系统
注释:文件系统技术规范(Filesystems Technical Specification)的内容现在是C++的一部分。 文件系统库允许以可移植的方式与目录和类似目录的结构进行交互