我有一些模板类,它们分为头文件和实现文件:
// MyTemplate.h
template<class T>
class MyTemplate {
public:
void Foo();
};
// MyTemplate.cpp
#include "MyTemplate.h"
template<class T>
void MyTemplate<T>::Foo() {
// ...
}
要在另一个翻译单元中使用
MyTemplate
,我可以 #include
实现文件:
#include "MyTemplate.cpp"
template class MyTemplate<int>;
这样我就可以:
我正在转换为 C++ 模块。当我不再使用
#include
时,有什么方法可以通过模块实现相同的效果吗?
在模块中,只需创建一个接口分区即可轻松完成此操作。这必须是一个 interface 分区,因为模板定义仍然是接口的一部分,因此它必须对导入它的人可见(就像常规 C++ 一样)。
按如下方式完成:
//Primary interface module
export module MyTemplates;
export import :TemplateDef;
//Other stuff for your module.
//Definition for your template.
export module MyTemplates:TemplateDef;
import :TemplateDecl;
template<class T>
export void MyTemplate<T>::Foo() {
// ...
}
//Declaration for your template
export module MyTemplates:TemplateDecl;
template<class T>
export class MyTemplate {
public:
void Foo();
};
话虽这么说,因为定义必须提供给每个人,所以将它们分成两个文件几乎没有什么好处。如果更改定义文件,则每个导入模块的人仍然需要重新编译。这就是模板的工作原理。
请注意,代码的非模块化形式非常糟糕。将模板实现与接口分离是可以的;使用名为“.cpp”的文件来执行此操作是不是。标头是要包含在内的;这就是为什么我们称它们为“标题”。用户在看到扩展名为“.cpp”的文件时会做出的假设是,该文件不应该被包含在内。
只需使用“.h”扩展名即可。 “.hxx”也经常用于实现(应该包含在“.h”版本中)。
在不使用模块的情况下,我发现人们通常有两种方法:
file.h
和file_impl.h
。您可以在 file_impl.h
末尾添加 file.h
。这与在文件末尾的类声明之后的所有模板定义基本相同。这就是我现在所做的。file.h
和 file.cpp
。然后,您在 .cpp
文件末尾进行一些显式实例化。 .cpp
必须被编译和链接。缺点是您必须先定义允许哪些模板实例化,并且不能(您不能???)使用其他类型。我想建议第三种方法。我会在我的下一个项目中尝试它,因为我认为
meson
和 ninja
不适用于 C++ 模块。
使用声明创建
mylib.h
。使用模板定义创建一个 mylib_impl.h
。创建一个 mylib.cpp
... 并使其包含 mylib_impl.h
并为最常用的类型进行显式实例化。
请注意,
mylib_impl.h
将会#include "mylib.h"
。但 mylib.h
末尾不会包含 mylib_impl.h
。
现在,大多数人都会包括
mylib.h
。如果该用户碰巧需要一些“非标准”类型,则用户必须包含 mylib_impl.h
或将此新实例添加到 mylib.cpp
。
可能需要教育用户很少使用
mylib_impl.h
。文档很重要,因为包含 mylib_impl.h
永远不会导致链接器错误,而 mylib.h
可能会导致链接器错误。
此外,还必须链接到
mylib.cpp
。
最后,如果我说了什么蠢话,我很抱歉。请耐心等待。 :-)