c++中的模板实例化问题
在c++中,模板是非常常见并且好用的。基本每一个c++的库都会使用模板,对自己的适用类型进行扩展。本文主要讲的是模板的实例化问题。
函数模板
类模板
模板实例化
当模板被使用时才会实例化,这一特性意味着,相同的实例可能出现在多个对象文件中。举个例子就是说,当两个或多个独立编译的源文件使用了相同的模板,并提供了相同的模板参数时,每个文件中都会有该模板适用该参数的一个实例。
上述的问题在小程序里不算什么,但是在一个大的程序中,在多个文件中实例化相同模板的额外开销会非常严重。
在新标准中,我们可以通过控制显式实例化来避免这种开销。
控制实例化
与多文件中声明一个变量相同,可以使用关键字extern
来承诺在程序其他位置会有一个该实例化的非extern
声明,只需要在链接成可执行程序时将含有实例化的.o
文件链接上就可以了。因此使用关键字extern
进行一个模板的声明时不会在本文件中生成实例化代码。
extern template declaration; //实例化声明
template decaration; //实例化定义
如下演示一下具体如何操作: 在第一个文件中, 1
2
3
4//templatebuild.cpp
//实例化文件必须为每个在其他文件中声明为extern的类型和函数提供一个(非extern)的定义
template int compare(const int&, const int&);
template class Blob<string>;1
2
3
4
5
6
7//application.cpp
//这些模板类型必须在其他位置已经进行实例化
extern template class Blob<string>; //声明,接下来就可以使用类Blob<string>了
Blob<string> b1; //像一个普通的类一样使用
extern template int compare(const int&, const int&);
int i=1,j=2;
int k = compare(i,j);templatebuild.o
与application.o
链接到一起,生成可执行文件。
类模板的实例化定义
此外,需要说明的一点是,一个类模板的实例化定义会实例化该模板的所有成员,包括内联的成员函数。
默认情况下,一个类模板的成员函数只有当程序用到它是才会进行实例化。但是一个类模板的实例化定义会实例化该模板的所有成员。这是因为当编译器遇到一个实例化定义时,它不了解程序使用哪些成员函数。因此与处理类模板的普通实例化不同,编译器会实例化该类的所有成员。即使我们不使用某个成员,它也会被实例化。因此,如果我们使用一个类型来显式实例化一个类模板,则这个类型必须能用于模板的所有成员。
参考资料
- [1] C++ Primer(第5版)