模块影响两件事:名称的范围和声明的可达性。仅当它们位于模块的权限范围内时(即:在导入的模块接口 TU 中并且不在全局模块片段中),这两者才重要。
在模块权限内声明的名称只有在以下情况下才可以在该模块外部使用:export
由该模块编辑。在显式模板实例化的情况下,模板itself已导出,因此模块外部的用户已经可以使用该名称。
然而,显式模板实例化定义也是一种声明。模块控制声明的可达性。事情是,声明的可达性规则 https://timsong-cpp.github.io/cppwp/n4861/module.reach#3实际上并不care about export
:
如果对于实例化上下文([module.context])中的任何点 P,声明 D 是可达的,
- 在同一翻译单元中,D 出现在 P 之前,或者
- D 不会被丢弃([module.global.frag]),出现在可从 P 到达的翻译单元中,并且不会出现在私有模块片段中。
[注:声明是否导出没有轴承关于是否可达。 ——尾注]
添加了强调。
这些规则只关心哪些 TU 已被导入(以及声明是否在全局/私有模块片段中)。
因此,如果主模板声明是export
ed,显式模板实例化(即not在导入的模块文件之一中的全局/私有模块片段中)可由导入它的任何代码访问。
所以如果你也没关系export
显式模板实例化。如果主模板已经export
ed,它的名称已经可以使用,所以唯一重要的是显式模板实例化是否可见。
所以你的 #1 和 2 在功能上是等效的。并且最好不要export
一些你不需要的东西。
至于行为extern template
, 那很有意思。
While extern
规范化表示外部链接,这不适用于extern template
。所以我们不存在链接问题。并且自从extern template
模块的导入者可以访问声明(如前所述),他们会看到它并尊重它。
所以唯一的问题是是否明确定义在你的“mod_impl.cpp”中也是可以访问的。但这不是一个问题,因为只有宣言定义的一部分永远是“可达的”。也就是说,可达性仅对声明重要。
显式实例化定义位于不同的 TU 中。因此,它只会在该 TU 中实例化;导入模块的代码仅到达声明。因此,它不会实例化模板。
所以是的,你可以执行extern template
体操(尽管如此,export
没关系)。但这与将显式实例化放入模块接口中没有什么不同,而且这样做更干净。