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 模块片段中)。
因此,如果主模板声明是 export
ed,一个显式模板实例化(即 不是 在 global/private 模块片段中)在一个导入模块文件的任何代码都可以访问它。
因此,如果您 export
显式模板实例化并不重要。如果主模板已经 export
ed,它的名称可能已经被使用,所以唯一重要的是显式模板实例化是否可见。
所以你的#1 和 2 在功能上是等价的。最好不要 export
不需要的东西。
至于extern template
的行为,很有意思。
虽然 extern
规范化表示外部链接,但这不适用于 extern template
。所以我们没有链接问题。由于 extern template
声明可以被模块的导入者访问(如前所述),他们会看到并尊重它。
所以唯一的问题是您的“mod_impl.cpp”中的显式 定义 是否也可以访问。但这不是问题,因为只有定义的 声明 部分是“可访问的”。也就是说,reach-ability 只对声明有影响。
显式实例化定义在不同的 TU 中。因此,它只会在那个TU中被实例化;导入模块的代码仅到达声明。因此,它不会实例化模板。
所以是的,您可以进行 extern template
体操(尽管 export
并不重要)。但这与将显式实例化放在模块接口中没有什么不同,而且这样做更简洁。
我正在创建一个库,我在 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 模块片段中)。
因此,如果主模板声明是 export
ed,一个显式模板实例化(即 不是 在 global/private 模块片段中)在一个导入模块文件的任何代码都可以访问它。
因此,如果您 export
显式模板实例化并不重要。如果主模板已经 export
ed,它的名称可能已经被使用,所以唯一重要的是显式模板实例化是否可见。
所以你的#1 和 2 在功能上是等价的。最好不要 export
不需要的东西。
至于extern template
的行为,很有意思。
虽然 extern
规范化表示外部链接,但这不适用于 extern template
。所以我们没有链接问题。由于 extern template
声明可以被模块的导入者访问(如前所述),他们会看到并尊重它。
所以唯一的问题是您的“mod_impl.cpp”中的显式 定义 是否也可以访问。但这不是问题,因为只有定义的 声明 部分是“可访问的”。也就是说,reach-ability 只对声明有影响。
显式实例化定义在不同的 TU 中。因此,它只会在那个TU中被实例化;导入模块的代码仅到达声明。因此,它不会实例化模板。
所以是的,您可以进行 extern template
体操(尽管 export
并不重要)。但这与将显式实例化放在模块接口中没有什么不同,而且这样做更简洁。