如何在 C++20 模块中使用模板显式实例化?

Cir*_*四事件 10 c++ templates c++20 c++-modules

本答案中所述,模板实例化允许减少编译时间和大小,因为不需要为使用它们的每个新文件中的每个新类型重新编译模板。

我也很高兴C++20 模块应该如何提供一个干净的解决方案来向外部项目公开模板并减少 hpp/cpp 重复。

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

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

helloworld.cpp

export module helloworld;
import <iostream>;

template<class T>
export void hello(T t) {
    std::cout << t << std::end;
}
Run Code Online (Sandbox Code Playgroud)

helloworld_impl.cpp

export module helloworld_impl;
import helloworld;

// Explicit instantiation
template class hello<int>;
Run Code Online (Sandbox Code Playgroud)

主程序

// 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);
}
Run Code Online (Sandbox Code Playgroud)

然后在https://quuxplusone.github.io/blog/2019/11/07/modular-hello-world 中提到的编译将进行(?)

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
Run Code Online (Sandbox Code Playgroud)

理想情况下,我还希望模板定义可用于外部项目。

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

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

这基本上是我在 C++20 之前的“从包含的头文件中删除定义但也公开模板和外部 API”中实现的,但该设置需要将接口复制两次,这似乎是模块系统本质上可以为我们做的事情。

Dav*_*ing 3

模块使 \xe2\x80\x9cfast 单一构建\xe2\x80\x9d 的情况变得非常容易。它们对 \xe2\x80\x99c 支持客户端实例化没有做太多工作,但避免重建显式实例化专业化 \xe2\x80\x9d 情况的客户端;从理论上讲,由于避免重复工作,构建速度通常会更快,因此无需扭曲程序即可节省更多时间。

\n\n

您所做的就是在模块接口中放置显式实例化定义:

\n\n
export module A;\nexport template<class T>\ninline void f(T &t) {++t;}\ntemplate void f(int&);\ntemplate void f(int*&);\n
Run Code Online (Sandbox Code Playgroud)\n\n

f即使函数模板是内联的(这可能需要在非模块化代码中进行额外的实例化) ,导入器也不必实例化这两种类型中的任何一种。典型的实现将这些实例化的结果缓存在已编译的模块接口文件中,并提供足够的详细信息,以便在导入器中进行内联调用(以及缓存模板本身,提供足够的详细信息以进一步实例化它)。

\n\n

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

\n