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.oapplication.o链接到一起,生成可执行文件。

类模板的实例化定义

此外,需要说明的一点是,一个类模板的实例化定义会实例化该模板的所有成员,包括内联的成员函数。

默认情况下,一个类模板的成员函数只有当程序用到它是才会进行实例化。但是一个类模板的实例化定义会实例化该模板的所有成员。这是因为当编译器遇到一个实例化定义时,它不了解程序使用哪些成员函数。因此与处理类模板的普通实例化不同,编译器会实例化该类的所有成员。即使我们不使用某个成员,它也会被实例化。因此,如果我们使用一个类型来显式实例化一个类模板,则这个类型必须能用于模板的所有成员。

参考资料

  • [1] C++ Primer(第5版)

c++中的模板实例化问题
http://line.com/2018/11/03/2018-11-03-cpp-template-class/
作者
Line
发布于
2018年11月3日
许可协议