C++20 模块导出模板实例化

C++20 modules export template instantiation

我正在创建一个库,我在 C++20 模块中有一个 class 模板,我想添加一个实例化以减少每个使用我的库的项目的编译时间。

这些不同的实现是等效的,还是有更好的实现方式?

1)

//mod.cpp
export module mod;

export template<typename T>
struct mystruct{ T i;};

export template class mystruct<int>;
//mod.cpp
export module mod;

export template<typename T>
struct mystruct{ T i;};

template class mystruct<int>;
//mod.cpp
export module mod;

export template<typename T>
struct mystruct{ T i;};

export extern template class mystruct<int>;



//mod_impl.cpp
module mod;

template class mystruct<int>;

编辑This answer 只说 2. 有效,但我的观点是如果 1. 和 3. 也等同于 2.

模块影响两件事:名称的范围和声明的可达性。这两个只有在模块的范围内才有意义(即:在导入的模块接口 TU 中而不是在全局模块片段中)。

在模块范围内声明的名称只有在被该模块export编辑时才能在该模块外使用。在显式模板实例化的情况下,模板 本身 已经导出,因此模块外的用户已经可以使用该名称。

但是,显式模板实例化定义也是一种声明。模块控制声明的可达性。问题是,the rules of reach-ability for a declaration 实际上 并不关心 关于 export:

A declaration D is reachable if, for any point P in the instantiation context ([module.context]),

  • D appears prior to P in the same translation unit, or
  • D is not discarded ([module.global.frag]), appears in a translation unit that is reachable from P, and does not appear within a private-module-fragment.

[ Note: Whether a declaration is exported has no bearing on whether it is reachable. — end note ]

添加了重点。

这些规则只关心导入了哪些 TU(以及声明是否在 global/private 模块片段中)。

因此,如果主模板声明是 exported,一个显式模板实例化(即 不是 在 global/private 模块片段中)在一个导入模块文件的任何代码都可以访问它。

因此,如果您 export 显式模板实例化并不重要。如果主模板已经 exported,它的名称可能已经被使用,所以唯一重要的是显式模板实例化是否可见。

所以你的#1 和 2 在功能上是等价的。最好不要 export 不需要的东西。


至于extern template的行为,很有意思。

虽然 extern 规范化表示外部链接,但这不适用于 extern template。所以我们没有链接问题。由于 extern template 声明可以被模块的导入者访问(如前所述),他们会看到并尊重它。

所以唯一的问题是您的“mod_impl.cpp”中的显式 定义 是否也可以访问。但这不是问题,因为只有定义的 声明 部分是“可访问的”。也就是说,reach-ability 只对声明有影响。

显式实例化定义在不同的 TU 中。因此,它只会在那个TU中被实例化;导入模块的代码仅到达声明。因此,它不会实例化模板。

所以是的,您可以进行 extern template 体操(尽管 export 并不重要)。但这与将显式实例化放在模块接口中没有什么不同,而且这样做更简洁。