显式实例化:
C++中模板函数(类)的调用与定义分离时,需要使用显式实例化,否则就会出现链接错误。
编译器对各个cpp分别编译的时候,模板函数必须被实例化编译。如果我们把调用与定义写在一个文件,在调用语句处有int a, b; cmp(a, b); 那么编译器就会知道我们将要使用cmp,然后结合该模板函数的定义语句,最后就编译出这么一个函数。问题就出现在我们把调用与定义写在不同的文件里,当编译器编译定义函数的cpp的时候,即便这个cpp有include该模板函数的头文件,编译器仍然不知道你的实例化typename是什么,因此这个.o就不会含实例化的函数。而编译器编译调用函数的cpp的时候,即便这个cpp也include了函数的头文件,但是由于没有定义,这个.o也不含实例化的函数。最后链接该定义cpp的.o和调用cpp的.o的时候,会找不到相应的实例化函数而报错。
//Example.h
template<class T>
class Test {
public:
Do(T a);
};
//Example.cpp
#include "Example.h"
template<class T>
Test::Do(T a) {
//do nothing...
}
//template class Test<int>; //注意显示实例化的语法,用<>符号指示类型
当保留最后一行的时候,编译Example.cpp输出汇编语言会得到一大块东西,而注释掉最后一行后就只剩下
.file “Example.cpp”
.ident “GCC: (tdm64-2) 4.8.1”
显然是没有代码被生成的,调用cpp产生的.o在链接example.o的时候就会出现链接错误。
显式具体化:
假设定义了如下结构:
struct job
{
char name[40];
double salary;
int floor;
};
另外,假设希望能够交换两个这种结构的内容。原来的模板使用下面的代码来完成交换:
temp = a;
a = b;
b = temp;
原来的模板使用下面的代码来完成交换, 它只能完成int,float等常规类型变量的交换,而如果是自定义的复杂结构体,则无法处理。因此类似于重载一样,我们要具体化一个特例template<> void Swap(job &j1, job &j2):
template<typename T>
void Swap(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
template<> void Swap<job>(job &j1, job &j2)//显式具体化在关键字template后包含<>,而显式实例化没有
{
double t1;
int t2;
t1 = j1.salary;
j1.salary = j2.salary;
j2.salary = t1;
t2 = j1.floor;
j1.floor = j2.floor;
j2.floor = t2;
}
void Show(job &j)
{
cout << j.name << ": $" << j.salary
<< " on floor " << j.floor << endl;
}
int main()
{
cout.precision(2);
cout.setf(ios::fixed, ios::floatfield);
int i = 10, j = 20;
cout << "i, j = " << i << ", " << j << ".\n";
cout << "Using compiler-generated int swapper:\n";
Swap(i, j);
cout << "Now i, j = " << i << ", " << j << ".\n\n";
job sue = {"Susan Yaffee", 73000.60, 7};
job sidney = {"Sidney Taffee", 78060.72, 9};
cout << "Before job swapping:\n";
Show(sue);
Show(sidney);
Swap(sue, sidney);
cout << "After job swapping:\n";
Show(sue);
Show(sidney);
return 0;
}