博客 阅读时间 5 分钟

C++ 最好的部分还在后面

分享本文
The best of C++ is what's coming

自 2011 年以来,许多新特性被加入到 C++ 标准中。有些特性,如 auto 和 nullptr,现在已被广泛使用,而另一些则相对少见。然而,一些最重要的变化——那些有潜力将这门语言提升到新高度的特性——仍在酝酿之中。

模块(Modules)

遗留的

#include

机制仍然存在,而且它有许多缺点,以下是这份有趣的文档中列出的一些。

  • 编译期可扩展性:每次包含一个头文件时,编译器都必须预处理和解析该头文件中的文本,以及它传递性包含的所有头文件。这个过程必须为应用中的每个翻译单元重复执行,这涉及大量的重复工作。在一个有N个翻译单元、每个翻译单元包含M个头文件的项目中,编译器要执行M x N的工作,尽管M个头文件中的大多数在多个翻译单元之间共享。C++ 在这方面尤其糟糕,因为模板的编译模型迫使海量代码进入头文件。
  • 脆弱性中对元类的定义以及使用它们的好处:#include指令被预处理器视为文本包含,因此会受到包含时任何生效的宏定义的影响。如果任何生效的宏定义恰好与库中的某个名称冲突,就可能破坏库 API 或导致库头文件本身编译失败。举个#define std "The C++ Standard"然后再包含一个标准库头文件的例子:结果是 C++ 标准库实现中一连串可怕的失败。更微妙的现实问题发生在两个不同库的头文件因宏冲突而相互影响时,用户被迫重新调整#include指令的顺序,或引入#undef指令来打破这种(无意的)依赖。
  • 惯用的变通方法:C 程序员采用了许多约定来规避 C 预处理模型的脆弱性。例如,绝大多数头文件都需要包含保护宏,以确保多次包含不会破坏编译。宏名以带长前缀的大写标识符书写以避免冲突,一些库/框架开发者甚至在头文件中使用__以下划线开头的名称,以避免与"普通"名称冲突——而那些名称(按约定)甚至不应该是宏。这些约定对来自非 C 语言的开发者构成了入门障碍,对更有经验的开发者来说则是样板代码,而且让我们的头文件变得远比应有的丑陋。
  • 工具的困惑:在基于 C 的语言中,很难构建与软件库良好协作的工具,因为库的边界不清晰。哪些头文件属于某个特定的库?这些头文件应该以什么顺序包含才能保证它们正确编译?这些头文件是 C、C++、Objective-C++,还是这些语言的某种变体?这些头文件中的哪些声明实际上属于 API 的一部分,又有哪些声明只是因为必须写在头文件里才存在的?

模块通过更健壮、更高效的语义模型改进了对库的访问。从用户的角度来看,代码看起来只有细微的差别,因为使用的是

import

声明而不是

#include

预处理器指令:

import std; // Module import directive.
int main() {
    std::cout << “Hello World\n”;
}

无需再包含众多 STL 头文件——一次 import 就足够了,代码因此更简洁。模块导入加载的是

std

模块的二进制表示,并使其 API 直接可供应用使用。位于 import 声明之前的预处理器定义对

std

提供的 API 没有任何影响,因为该模块本身是作为独立的模块单独编译的。

元类(MetaClass)

Herb Sutter 多年来一直致力于改进 C++,去年他提出了元类(metaclasses)特性。以下是他这篇博文中对元类的定义以及使用它们的好处:

我一直在研究一项实验性的 C++ 新语言特性,暂定名为"元类",旨在让 C++ 编程既更强大又更简单。

以下是提案中对元类的定义以及使用它们的好处:

元类(暂定名)让程序员能够编写一种新的高效抽象:通过编写从普通 C++ 源代码到普通 C++ 类定义的自定义变换,定义一个共享公共特征(包括用户自定义的规则、默认值和生成的函数)的类的命名子集。不存在类型系统的分裂;生成的类就是一个普通的类。主要目标:• 将 C++ 的抽象词汇扩展到 class/struct/union/enum 之外——这些是硬编码在语言中的类型类别。• 使长期以来的最佳实践能够以可复用库的形式提供,而不是以英文指南/书籍的形式提供,从而拥有易于采用的词汇(如 interface、value),而不是需要记忆的规则清单(如:记住要用这个编码模式来编写抽象基类或值类型,并依赖工具来发现错误)。• 能够为任何目的编写由编译器强制执行的模式:编码标准(如许多核心指南的"强制"规则)、API 要求(如类要与硬件接口库、浏览器扩展、回调机制协作所必须遵循的规则),以及任何其他针对类的模式。• 能够以普通库代码的形式编写许多新的"专用类型"特性(如我们在 C++ 11 中对 enum class 所做的那样),而不是用伪英语式的标准文体,并具有同等的可用性和效率,使它们可以用普通工具进行单元测试和调试,无需更新/发布新编译器即可开发和分发,并且以代码的形式通过 LEWG/LWG 审议,而不是以标准文体的形式通过 EWG/CWG。这样一来,我们就能将那些有价值的扩展标准化——它们因为太狭窄(如 interface)而可能永远不会被纳入核心语言,但可以很容易地作为小型自包含的库来标准化。• 消除发明非 C++"辅助语言"和专用编译器(如 Qt moc、COM MIDL 和 C++/CX)的需要——这些工具的存在是为了表达它们的系统需要、但今天的 C++ 无法表达的信息(如属性、事件回调等专用类型和类似抽象)。

有了模块和元类,C++ 可以变得既更强大又更易用,未来还可能会加入更多特性。我们只能说:感谢所有持续改进这门语言的 C++ 贡献者——C++ 万岁!:)

分享本文