使用extern模板(C ++ 11)
图1: function模板
TemplHeader.h
template<typename T> void f();
TemplCpp.cpp
template<typename T> void f(){ //... } //explicit instantation template void f<T>();
Main.cpp的
#include "TemplHeader.h" extern template void f<T>(); //is this correct? int main() { f<char>(); return 0; }
这是使用extern template
的正确方法吗,还是仅使用此关键字作为类模板,如图2所示?
图2: 类模板
TemplHeader.h
template<typename T> class foo { T f(); };
TemplCpp.cpp
template<typename T> void foo<T>::f() { //... } //explicit instantation template class foo<int>;
Main.cpp的
#include "TemplHeader.h" extern template class foo<int>(); int main() { foo<int> test; return 0; }
我知道将所有这些放在一个头文件中是好的,但是如果我们在多个文件中实例化具有相同参数的模板,那么我们得到了多个相同的定义,编译器将会除去它们(除了一个)以避免错误。 我如何使用extern template
? 我们可以只用于类,还是我们可以用它的function呢?
另外,图1和图2可以扩展到一个解决scheme,其中模板位于单个头文件中。 在这种情况下,我们需要使用extern template
关键字来避免多个相同的instantations。 这只是为了类或function吗?
您应该只使用extern template
来强制编译器在您知道将在其他地方实例化时不实例化模板。 它用于减less编译时间和目标文件大小。
例如:
// header.h template<typename T> void ReallyBigFunction() { // Body } // source1.cpp #include "header.h" void something1() { ReallyBigFunction<int>(); } // source2.cpp #include "header.h" void something2() { ReallyBigFunction<int>(); }
这将导致以下目标文件:
source1.o void something1() void ReallyBigFunction<int>() // Compiled first time source2.o void something2() void ReallyBigFunction<int>() // Compiled second time
如果两个文件都链接在一起,则会丢弃一个void ReallyBigFunction<int>()
,导致浪费的编译时间和目标文件大小。
为了不浪费编译时间和目标文件大小,有一个extern
关键字,它使编译器不能编译模板函数。 你应该使用这个当且仅当你知道它被用在其他地方的相同的二进制文件。
将source2.cpp
更改为:
// source2.cpp #include "header.h" extern template void ReallyBigFunction<int>(); void something2() { ReallyBigFunction<int>(); }
将导致以下目标文件:
source1.o void something1() void ReallyBigFunction<int>() // compiled just one time source2.o void something2() // No ReallyBigFunction<int> here because of the extern
当这两个将被链接在一起时,第二个目标文件将只使用第一个目标文件中的符号。 不需要丢弃,也不需要浪费编译时间和目标文件大小。
这应该只在一个项目中使用,就像在多次使用vector<int>
这样的模板的时候,除了一个源文件之外,你应该使用extern
。
这也适用于类和函数作为一个,甚至模板成员函数。
维基百科有最好的描述
在C ++ 03中,只要在翻译单元中遇到完全指定的模板,编译器就必须实例化一个模板。 如果模板在许多翻译单元中使用相同的types实例化,这可以大大增加编译时间。 在C ++ 03中没有办法阻止这个,所以C ++ 11引入了extern模板声明,类似于extern数据声明。
C ++ 03有这样的语法来强制编译器实例化一个模板:
template class std::vector<MyClass>;
C ++ 11现在提供了这个语法:
extern template class std::vector<MyClass>;
它告诉编译器不要在这个翻译单元中实例化模板。
警告:使用nonstandard extension used...
微软的VC ++过去几年已经有了这个function的非标准版本 (在C ++ 03中)。 编译器警告说为了防止需要在不同编译器上编译的代码的可移植性问题。
看看链接页面中的示例,看看它的工作方式大致相同。 您可以期望消息与未来版本的MSVC消失,当然除了同时使用其他非标准的编译器扩展。
模板的已知问题是代码膨胀,这是在调用类模板特化的每个模块中生成类定义的结果。 为了防止这种情况,从C ++ 0x开始,可以在类模板专门化之前使用关键字extern
#include <MyClass> extern class CMyClass<int>;
模板类的显式实例应该只发生在一个单独的翻译单元中,最好是具有模板定义的单元(MyClass.cpp)
template class CMyClass<int>; template class CMyClass<float>;
如果你之前使用过extern函数,那么模板就完全一样。 如果没有,简单的functionextern虽然可能会有所帮助。 另外,您可能需要将外部文件放在头文件中,并在需要时包含头文件。