有时候,确实需要多次调用一个包含文件;在许多情况下,这是可取的。其中一个例子是优化大型复杂模板的实例化。考虑一些典型的大型复杂模板类。
template<typename T> class ComplicatedTemplate {
};
拥有这个庞大的模板在每个翻译单元中被实例化和编译,对于同一模板类型,反复进行,变得非常老旧。它会减慢编译速度,并不必要地膨胀每个对象模块,只是让链接器处理剥离出大量重复的模板实例化。这是很多浪费的工作。
许多编译器提供控制模板实例化的方法。具体细节可能有所不同,但我将使用典型方法,如gcc所使用的方法,您可以在此处阅读:
https://gcc.gnu.org/onlinedocs/gcc/Template-Instantiation.html
假设您想要在名为 "complicated.cpp" 的翻译单元中实例化 ComplicatedTemplate<std::vector<int>>
,ComplicatedTemplate<std::vector<char>>
和ComplicatedTemplate<std::string<std::string>>
,只需在头文件中声明为 extern。
因此,您最终会得到这个complicated_template.H
文件。
template<typename T> class ComplicatedTemplate {
};
extern template ComplicatedTemplate<std::vector<int>>;
extern template ComplicatedTemplate<std::vector<char>>;
extern template ComplicatedTemplate<std::vector<std::string>>;
然后,在 complicated.cpp
中:
#include "complicated_template.H"
template ComplicatedTemplate<std::vector<int>>;
template ComplicatedTemplate<std::vector<char>>;
template ComplicatedTemplate<std::vector<std::string>>;
好的,那么这将很好地工作,除了一个不便之外。如果您决定还要添加ComplicatedTemplate<std::vector<SomeCustomType>>
或其他任何预实例化模板,需要在两个地方进行操作;即头文件和complicated.cpp
文件。
以下是消除此重复的典型方法:
complicated_template.H
:
template<typename T> class ComplicatedTemplate {
};
#include "complicated_template_inst.H"
complicated_template_inst.H
:
EXTERN template ComplicatedTemplate<std::vector<int>>
EXTERN template ComplicatedTemplate<std::vector<char>>
EXTERN template ComplicatedTemplate<std::vector<std::string>>
然后,在complicated.cpp
文件中:
现在,预先实例化的模板实例列表在一个地方。使用之前的示例,添加:
EXTERN template ComplicatedTemplate<std::vector<SomeCustomType>>
这种方法既可以防止在需要该模板实例的每个翻译单元中浪费实例化,又可以在 complicated.cpp
翻译单元中显式实例化它。
在许多大型的 C++ 库中都可以看到这种做法。通常情况下,它们会定义模板,然后通过引用一个包含一些预处理操作的单独 #include 文件来进行预实例化。实际的共享库还将第二个文件再次包含进去,在拉取外部可见头文件之后,通过相应的预处理器配置将那些外部模板声明转换为模板实例化。
#include <header.h>
的内容首先由预处理器处理,它基本上将头文件的内容放入主文件中,因此编译器看到的是大量重复的代码。 - rendon#include
同一个文件有用的SO帖子。https://dev59.com/j2gv5IYBdhLWcg3wDsnZ - R Sahu