Skip to content

JEP 347: Enable C++14 Language Features | 启用 C++14 语言特性

摘要

允许在 JDK C++ 源代码中使用 C++14 语言特性,并给出关于哪些特性可以在热点代码中使用的具体指导。

目标

通过 JDK 15,JDK 中 C++ 代码所使用的语言特性已经被限制到 C++98/03 语言标准。在 JDK 11 中,代码被更新以支持用新版本的 C++ 标准构建,尽管它还没有使用任何新的特性。这包括能够使用支持 C++11/14 语言特性的各种编译器的最新版本进行构建。

该 JEP 的目的是正式允许在 JDK 内更改 C++ 源代码,以利用 C++14 语言的特性,并就哪些特性可用于热点代码给出具体指导。

非目标

本 JEP 不建议对 HotSpot 之外的 JDK 中的 C++ 代码进行任何用法或样式更改。热点和非热点代码的规则已经不同。例如,C++ 异常被用在一些非 HotSpot 代码中,但是在 HotSpot 中被构建时选项禁止。然而,构建一致性要求将使更新的语言特性可用于 JDK 中的所有 C++ 代码。

描述

对构建系统的更改

为了利用 C++14 语言的特性,需要进行一些编译时的更改,具体取决于平台编译器。还需要指定各种平台编译器的最低可接受版本。应明确规定所需的语言标准;较新的编译器版本可能默认为较新的、可能不兼容的语言标准。

  • windows:JDK 11 需要 Visual Studio 2017。(早期版本会生成配置时警告,可能会也可能不会工作。) 对于 Visual Studio 2017,默认的 C++ 标准是 C++14。这 /std:c\+\+14 应添加选项。对旧版本的支持将被完全放弃。

  • Linux: 替换 -std=gnu++98 编译器选项 -std=c\+\+14。gcc 支持的最低版本是 5.0。

  • macOS: 替换 -std=gnu++98 编译器选项 -std=c\+\+14。clang 支持的最低版本是 3.5。

  • AIX/PowerPC: 替换 -std=gnu++98 编译器选项 -std=c\+\+14 并且要求使用 xlclang++ 作为编译器。xlclang++ 支持的最低版本是 16.1。

HotSpot 代码中 C++ 用法的更改

在 HotSpot 代码中使用 C++ 的现有限制和最佳实践建议基于 C++98/03 语言标准,并在 热点样式指南.

我们将在该文档中为更新的语言标准添加类似的限制和指南。它们将由一个允许特性表和另一个排除特性表来描述。使用许可功能可能是无条件的,也可能有一些限制或附加指导。在热点代码中禁止使用被排除的特性。

还有第三类,未决定的特性,关于这一点,热点开发者还没有达成共识,或者可能根本没有讨论过。也禁止使用这些功能。

但是,请注意,一些语言特性的使用可能不会立即显现出来,而且可能会意外地出现,因为编译器会接受它们。与往常一样,代码审查过程是对此的主要防御。

对功能分类的建议更改由以下人员批准 粗略的共识 热点组成员的,由组领导确定。此类变更必须记录在风格指南的更新中。

C++11 和 C++14 的新特性列表,以及它们的描述链接,可以在一些编译器和库的在线文档中找到:

根据经验,鼓励允许简化代码编写,尤其是代码阅读的特性。

HotSpot 在很大程度上避免了使用 C++ 标准库。其中的一些原因可能已经过时了 (特别是早期版本中遇到的错误),而另一些原因可能仍然适用 (最小化依赖性)。标准库的分类应该经历与语言特性相同的过程。

下面是热点的一组初始特征分类。

允许

  • constexpr

    • 放松对…的要求 constexpr 功能 (n3652)
    • 广义常数表达式 (n2235)

    放松的 constexpr(n3652) 也许是区别 C++14 和 C++11 的关键特性。这 constexpr 特性将允许消除一些笨拙的宏代码 constexpr 功能。这个特性也是简化元编程习惯用法的基础。看见 mpl11mpl11_2.

  • 大小释放 (n3778)—由于 Visual Studio 的原因,语法已经在使用中。

  • 可变模板

    • 可变模板 (n2242)
    • 扩展可变模板模板参数 (n2555)

    可能只是偶尔直接有用,但对于简化的元编程习惯用法 (如 mpl11mpl11_2.

  • 静态断言 (n1720)—替换 HotSpot STATIC_ASSERT 宏,提供更好的错误消息。

  • decltype

    • 表达式的声明类型 (n2343)
    • decltype 和呼叫表达式 (n3276)

    重要的元编程工具。需要实现一个简化的功能模板 SFINAE 实用程序。

  • 右尖括号 (n1757)—消除了一个烦人的语法错误。

  • 函数模板的默认模板参数 (CWG D226)—除了本身有用之外,它还需要实现一个简化的函数模板 SFINAE 实用程序。

  • 模板别名 (n2258)—带有模板参数的 Typedefs。为类模板的局部专门化提供语法,而不是使用继承 (有时以不适当的方式)。在元编程的简化方法中也用作元函数 mpl11mpl11_2.

  • 强类型枚举 (n2347)—允许显式控制枚举的基础类型,而不是让它潜在地由实现定义 (并且在实现之间有所不同)。还允许枚举类的强类型,消除了隐式转换。建议 作用域枚举 当枚举数确实是一组逻辑值时使用。使用 未分类枚举 是允许的,尽管当不使用自动初始化器特性时,普通常量应该是首选。这 枚举基 应该总是显式指定,而不是让它依赖于枚举值的范围和平台。

  • 委托构造函数 (1986 年)—通过允许专用构造函数链接到更通用的构造函数,消除一些代码重复和简化。

  • 显式转换运算符 (n2437)—用于确保某些现有转换运算符的安全。

  • 标准布局类型 (n2342)

  • 默认和删除的函数 (n2346)

  • 并发的动态初始化和销毁 (n2660)—线程安全函数—局部静态。

  • <type_traits> 是一个核心元编程库。它消除了对许多 HotSpot 元编程实用程序的需要,这些实用程序是在本库的相应部分上建模的。

  • final 类和虚函数的虚拟说明符 (n2928), (n3206), (n3272)—的 final 说明符允许虚函数调用的非虚拟化。这比依赖编译器使用诸如指向分析或推测性非虚拟化之类的技术可以提供更好的性能。这 overrides 虚函数的说明符,在参考文献中也有描述,可以在以后考虑。

  • 本地和未命名类型作为模板参数 (n2657)—当使用模板时,允许将使用过一次的帮助器类的本地定义放在使用点附近,而不需要在名称空间范围内定义这样的帮助器。

  • nullptrstd::nullptr_t (n2431)

  • auto 变量声明 (1984 年)—仅当它使代码更清晰或更安全时使用。不要仅仅为了避免编写显式类型的不便而使用它,除非该类型本身很难编写。对于局部变量,这可以通过消除明显或不相关的类型信息来使代码更加清晰。过度使用会使代码更难理解。

  • 函数返回类型演绎 (n3638)—仅在函数体的 return 语句,通常其他代码相对较少。

  • 表情 SFINAE(n2634)

排除

  • 新的字符串和字符文字

    • 新字符类型 (n2249)
    • Unicode 字符串文字 (n2442)
    • 原始字符串文字 (n2442)
    • 通用字符名称文字 (n2170)

    HotSpot 不需要任何新的字符和字符串类型。

  • 用户定义的文字 (n2765)—用户定义的文字不应随便添加,而只能通过添加特定 UDL 的建议来添加。

  • 内联名称空间 (n2535)— HotSpot 对名称空间的使用非常有限。

  • using namespace 指令。特别是,不要使用 using namespace std; 以避免需要限定标准库名。

  • 传播异常 (n2179)— HotSpot 不允许使用异常,所以这个特性没有用。

  • thread_local (n2659)—使用热点 THREAD_LOCAL 宏观;见讨论 JDK-8230877.

  • <atomic> (n2427), (n2752); 相反,使用热点 Atomic 班级和相关设施。

  • [[deprecated]] 属性 (n3760)—与热点代码无关。

其他一些项目的类似列表

风险和假设

可能有其他平台的工具链还不支持 C++14 语言标准。

某些编译器对某些新功能的支持可能存在缺陷。