42

我正在阅读论文A Module System for C++ 以了解 C++ 模块,这是 C++ 的一项提议功能。

我无法完全理解此模块架构将如何导出模板。

有任何想法吗?

4

1 回答 1

43

目前,C++ 实现实际上只有两个与代码相对应的“东西”:我们人工编写和编辑的源代码,以及编译器根据源代码输出的汇编。

因为 C++ 模板是“具体化”的,所以会为每个模板实例化生成单独的程序集。因此,不能在定义模板的地方生成任何程序集,而只能在使用它们的地方生成。这就是为什么模板必须位于头文件中的原因,因此它们基本上可以复制粘贴到使用点(这就是#include 的全部内容)。

这个想法是有代码的第三种表示形式。想象一下,编译器在解析代码之后但开始生成汇编之前在内部具有某种内部表示。它产生的“事物”最终是抽象语法树(AST)的某种表示。它基本上就是你的程序,从对人类最简单的形式映射到对计算机最简单的形式。

这是模块(或至少是它们的实现)背后的非常粗略的想法。你拿出你的代码,然后吐出某种代表 AST 的文件。此 AST 是您程序的完整表示,因此它是完全无损的。它知道你声明的模板的一切,等等。当一个模块被加载时,它只会加载这个文件,编译器可以完全使用它,就好像它拥有所有可用的源一样。但是,将人类可读的源代码转换为这个 AST 的步骤实际上是一个相当昂贵的步骤。从 AST 开始会快很多。

如果您只有一个翻译单元,这会比较慢。毕竟解析->codegen还是比解析->序列化->反序列化->codegen快。但是假设你有 10 个翻译单元,它们都是 #include 向量。您将解析向量中的代码 10 次。此时,序列化/反序列化的额外成本被您只需解析一次的事实所抵消(并且反序列化可以比解析快得多;这种数据格式将专门设计用于使反序列化快速,而源代码是设计为可读,向后兼容等)。

在某种意义上,预编译的标头是模块的预览:https ://clang.llvm.org/docs/PCHInternals.html

于 2017-05-09T07:38:05.417 回答