4

我开始尝试 Microsoft Visual Studio 的 C++ 模块实现。微软将标准库分为五个模块

  • 标准正则表达式
  • 标准文件系统
  • 标准内存
  • 标准线程
  • 标准核心

我已经用上述模块替换了我的标准库,适用于我项目中的每个文件。但是,我包含了许多第三方库文件。例如,一个第三方库在一个头文件中有一个,而我在包含第三方库的头文件之前#include <memory>已经在我的文件中。import std.memory;

模块是否std.memory定义了会导致第三方库跳过不必要的包含防护,#include <memory>或者它是否包含内存,即使模块覆盖<memory>已经包含在内?

标准对此有什么要说的吗?这似乎是向模块过渡期间的一个重要问题:如果使用第三方库,如果它们的包含仍然像以前一样出现,那么对模块的好处似乎会大大降低。

4

2 回答 2

2

C++20 根本没有为标准库指定模块。相反,它指定(大部分)库头文件可以被导入:import<vector>;等等。因此,无论是标准库组件附加到全局模块的情况,在这种情况下,假设的 C++23std.vector模块接口单元可能就像

module;
#include<vector>
export module std.vector;
namespace std {
  export using std::vector;
}

甚至

export module std.vector;
export import<vector>;

或者它们附加到一个命名模块,在这种情况下,标题<vector>可能只是

import std.vector;

(加上功能测试宏)。

在这两种情况下,如果翻译单元同时执行这两种操作,任何事情都不会中断

import std.vector;
#include<vector>

可能会发生在#include包含这些行的头文件中: 的两个定义std::vector在不同的翻译单元中,就像#include<vector>. 仍然存在效率问题:使用前一种策略,翻译单元可能会import#include相同的组件,并且命名模块无法提供宏来阻止对其进行重新解析。然而,使用这种策略的实现可能会选择将转换#includeanimport<vector>;来避免这种情况。

请注意,与 MSVC 的实现一样,C++23 标准库模块可能比头文件更粗糙,因此上述内容适用于 (say)std.containers<vector>, <deque>,<map>

于 2020-09-11T19:29:28.803 回答
0

指令的确切#include <vector>作用取决于实现。该实现可以有一种机制来检测vector模块包含的内容以及vector由于模块而已经可用的定义import。在这种情况下,#include <vector>指令可能什么也不做,或者#include文件是空的。

一旦 C++ 标准库在实际标准中被模块化,并且随着模块实现的成熟,这些东西可能只是实现的一部分。但是,此类优化将基于编译器特定的内在函数或编译器拥有的显式逻辑。它不一定适用于第 3 方,因此总体问题仍然存在。

解决该问题的主要方法是不在#include模块中使用第 3 方 API 标头;你import这样的标题。这就是为什么标头import指令是模块系统的一部分。通过importing 标头,您鼓励实现以确保此标头只编译一次。

现在是的,如果您import在每个10 上使用了 10 个头文件#include <vector>,那么<vector>这些模块头文件将被编译 10 次。但是,如果您import是项目中 10 个不同文件的其中一个头文件,则该头文件应该只编译一次。只有当这些头文件的内容发生变化时,此类imported 模块头文件才需要重新编译,因此项目的后续构建不应该需要重新处理 3rd 方 API。

于 2020-09-12T21:23:52.427 回答