为什么需要外部模板
先来看一个例子:
fun.h定义了模版函数fun, 在use1.cpp和use2.cpp中都使用了该模版函数,在编译这两个cpp文件时需要分别实例化, 这就涉及到性能问题。
//fun.h
template <typename T>
void fun(T t){
}
//use1.cpp
void test1(){
fun<int>(1);
}
//use2.cpp
void test2(){
fun<int>(1);
}
fun.h定义了模版函数fun, 在use1.cpp和use2.cpp中都使用了该模版函数,在编译这两个cpp文件时需要分别实例化, 这就涉及到性能问题。
对于源代码中出现的每一处模板实例化,编译器都需要去做实例化的工作;而在链接时,链接器还需要移除重复的实例化代码。
很明显,这样的工作太过冗余,而在广泛使用模板的项目中,由于编译器会产生大量冗余代码,会极大地增加编译器的编译时间和链接时间
extern关键字
为此C++ 11提出了“外部 模版” ,用于模板性能上的改进。 实际上,“外部”(extern)这个概念早在C的时候已经就有了。
通常情况下,我们在一个文件中a.c中定义了一个变量int i,而在另外一个文件b.c中想使用它,这个时候我们就会在没有定义变量i的b.c文件中做一个外部变量的声明。
比如:
extern int i;
这样在编译a.c目标文件包含i的定义, b.c目标文件只有i的符合链接; 在链接的时候生产的一个可执行文件只有一个i的实例。
外部模版
C++已经有了强制编译器在特定位置开始实例化的语法:
template class std::vector<MyClass>;
extern template class std::vector<MyClass>;
这样就告诉编译器不要在该编译单元内将该模板实例化。
采用外部模版,修改实例为:
//fun.h
template <typename T>
void fun(T t){
}
//use1.cpp
void test1(){
fun<int>(1);
}
//use2.cpp
extern template void fun<int>(int);
void test2(){
fun<int>(1);
}