C++ 如何将模板显式实例化与C++;20个模块?

C++ 如何将模板显式实例化与C++;20个模块?,c++,templates,c++20,c++-modules,C++,Templates,C++20,C++ Modules,如前所述,模板实例化通过不要求为使用模板的每个新文件中的每个新类型重新编译模板,从而减少了编译时间和大小 我还对如何提供一个干净的解决方案来向外部项目公开模板并减少hpp/cpp重复感到兴奋 允许它们一起工作的语法是什么 例如,我希望模块看起来有点像(未经测试,因此可能是错误的代码,因为我没有足够新的编译器/不确定它是否已经实现): helloworld.cpp export module helloworld; import <iostream>; template<cla

如前所述,模板实例化通过不要求为使用模板的每个新文件中的每个新类型重新编译模板,从而减少了编译时间和大小

我还对如何提供一个干净的解决方案来向外部项目公开模板并减少hpp/cpp重复感到兴奋

允许它们一起工作的语法是什么

例如,我希望模块看起来有点像(未经测试,因此可能是错误的代码,因为我没有足够新的编译器/不确定它是否已经实现):

helloworld.cpp

export module helloworld;
import <iostream>;

template<class T>
export void hello(T t) {
    std::cout << t << std::end;
}
理想情况下,我还希望模板定义在外部项目上可用

我想我想要的是一种导入模块的方法,并在导入时决定:

  • 使用模块中的所有模板,就好像它们只是声明一样(我将在另一个文件中提供我自己的实例化)
  • 将模块中的模板当作定义使用

这基本上是我在pre-C++20 at中实现的,但是设置需要复制两次接口,这似乎是模块系统基本上可以为我们做的事情。

模块使“快速单构建”案例变得非常简单。对于“支持客户机实例化,但避免重建显式实例化专门化的客户机”的情况,它们没有做很多工作;该理论认为,由于避免重复工作,构建速度通常更快,因此无需扭曲程序以节省更多时间

您所要做的就是在模块界面中放置一个显式实例化定义:

export module A;
export template<class T>
inline void f(T &t) {++t;}
template void f(int&);
template void f(int*&);
导出模块A;
导出模板
内联void f(T&T){++T;}
模板空f(int&);
模板空白f(int*&);
进口商不必为这两种类型中的任何一种实例化
f
,即使函数模板是内联的(这可能需要非模块化代码中的附加实例化)。典型的实现将这些实例化的结果缓存在已编译的模块接口文件中,并提供足够的详细信息以在导入器中内联调用(以及缓存模板本身,提供足够的详细信息以进一步实例化模板)


当然,您也可以在接口中使用显式实例化声明和模板声明,并定义模板,将显式实例化定义放入模块实现单元中,但这与头文件的工作方式没有什么不同。

您可以在模块接口(
helloworld.cpp
)中省略定义,而只将其包含在模块实现中。如果这真的达到了你想要的确切结果,我不能说,但这样做似乎是合理的。模块实现中没有导出任何内容。@super这是一种可能性,我希望模块能够提供更好的方式,而不需要像这样拆分实现和头(值得注意的是,对于同时使用该模块的外部项目,我需要像模块之前一样的三个文件:接口、实现和实例化,如“从包含的头中删除定义,但也公开外部API模板”中所述)如果您想公开模板定义,但同时又不必为某个类型重新设置它,那么您只需在定义后添加一个显式的重新设置。无需拆分任何内容。如果您想隐藏定义但为某些类型重新设置它,只需在接口/实现中拆分它即可我不理解你的推理…我不能肯定,因为模块是如此的新,但在我看来,对于模块,你不需要显式的实例化来获得编译时的速度提升。模块的要点是,模块的源代码将只处理一次,并存储在编译器友好的AST中,以便快速重用如果我不得不猜测的话,我会冒险让模板实例化得到同样的处理,也就是说,当你调用
hello
时,它的定义将被存储一次并重新使用。再一次,这只是我从我看过的所有关于模块的讨论中得出的一个有根据的推测。@bolov:模块的编译优势在于你不需要这样做每次导入模板时都要分析模板的文本。但是实例化是一个完全独立的问题,对于复杂的元编程来说,这可能仍然很慢。而且您仍然可以在不同的翻译单元中实例化同一模板;模块不会改变这一点。啊,好的,所以它可以用中间语言缓存实例化。幻想曲ic!我稍后会做一些基准测试。所以,可能对象文件仍然会有实例化的多个副本,但生成它们会更快。@CiroSantilli冠状病毒审查六四事件法轮功: 我们还应该期望得到模块接口的对象文件,它可以像往常一样保存链接器的实际对象代码一次。@CiroSantilli郝海东冠状病六四事件法轮功 你做了一些基准测试吗?我很有兴趣看到结果。@MatthieuG否:-)
// How to prevent the full definition from being imported here, which would lead
// hello(1) to instantiate a new `hello<int>` instead of reusing the explicit instantiated
// one from `helloworld_impl.cpp`?
import helloworld;

int main() {
    hello(1);
}
clang++ -std=c++2a -c helloworld.cpp -Xclang -emit-module-interface -o helloworld.pcm
clang++ -std=c++2a -c -fprebuilt-module-path=. -o helloworld_impl.o helloworld_impl.cpp
clang++ -std=c++2a -fprebuilt-module-path=. -o main.out main.cpp helloworld_impl.o
export module A;
export template<class T>
inline void f(T &t) {++t;}
template void f(int&);
template void f(int*&);