在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的一个方案。编译器在使用模板为特定类型生成函数定义时,得到的是模板实例。如下程序使用char类型,生成一个Swap的实例:
template <typename T>
void Swap(T& a, T& b); //< 函数模板
void main()
{
char g = 1;
char h = 2;
Swap(g, h); //g=2, h=1
}
template <typename T>
void Swap(T& a, T& b)
{
T tem;
tem = a;
a = b;
b = tem;
}
注意,模板并非函数定义,但使用char的的模板实例是函数定义,这种实例化方式叫做隐式实例化。
C++还允许使用显示实例化,其语法为:声明所需的种类(用<>符号指示),并在声明前加上关键字template。如下程序使用显示实例化生成了了一个int类型的函数定义:
template <typename T> //< 函数模板
void Swap(T& a, T& b);
template void Swap<int>(int &, int&); //< 使用Swap模板显示地生成int类型函数定义
void main()
{
char g = 1;
char h = 2;
Swap(g, h); //< 隐式实例化
int i = 10;
int j = 20;
Swap(i, j); //< 显示实例化
cout << "i = " << i << " " << "j = " << j << endl;
}
template <typename T>
void Swap(T& a, T& b)
{
T tem;
tem = a;
a = b;
b = tem;
}
到此产生了一个疑问,显示实例化有什么用呢?其实可以总结下二者的区别:
隐式实例化:后面有程序用了,编译器才会根据模板生成一个实例函数;
显式实例化:是无论是否有程序用,编译器都会生成一个实例函数;
另一个概念就是显示具体化,也就是特化,即使通用模板特殊化,当程序找到与函数调用匹配的具体化时,将使用该定义,而不再寻找模板。
显示具体化的原型和定义应以template<>打头,并通过名称来支出类型,可以使用下面两个等价的声明之一:
template<> void Swap<int>(int &c1, int &c2);
template<> void Swap(int &c1, int &c2);
意思就是,“不要使用Swap模板来生成函数定义,使用专门为int类型显示定义的函数定义”。
如下程序使用显示具体化完成Swap的特殊形式,即交换两个元素的一部分内容:
struct job
{
char name[40];
double salary;
int floor;
};
void show(job& j);
template <typename T> //< 函数模板
void Swap(T& a, T& b);
template void Swap<int>(int &, int&); //< 使用Swap模板显示地生成int类型函数定义
template<> void Swap<job>(job& j1, job& j2);//< 显示具体化,特化Swap模板
//< or
//template<> void Swap(job& j1, job& j2);//< 显示具体化,特化Swap模板
void main()
{
char g = 1;
char h = 2;
Swap(g, h); //< 隐式实例化
int i = 10;
int j = 20;
Swap(i, j); //< 显示实例化
cout << "i = " << i << " " << "j = " << j << endl;
job sue = { "susan",7300,7 };
job sidney = { "sidney",7800,5 };
Swap(sue, sidney); //< 使用显示具体化
show(sue); //< susan:$7800 on floor:5
show(sidney); //< sidey:$7300 on floor:7
}
template <typename T>
void Swap(T& a, T& b) //常规模板
{
T tem;
tem = a;
a = b;
b = tem;
}
template<> void Swap<job>(job& j1, job& j2) //< 显示具体化
{
double t1;
int t2;
t1 = j1.salary;
j1.salary = j2.salary;
j2.salary = t1;
t2 = j1.floor;
j1.floor = j2.floor;
j2.floor = t2;
//< 此处只交换了j1与j2的一部分
}
void show(job& j)
{
cout << j.name << ":$" << j.salary << " "
<< "on floor:" << j.floor << endl;
}
至此已经出现了显示实例化,隐式实例化,显示具体化,非模板函数(即普通函数),那么在函数调用时,是如何选取哪个函数版本呢?答案是:
具体化优先于常规模板,非模板函数优先于具体化和常规模板。
同时,显示实例化,隐式实例化,显示具体化统称为具体化。
struct job
{
char name[40];
double salary;
int floor;
};
void show(job& j);
template <typename T> //< 函数模板
void Swap(T& a, T& b);
template void Swap<int>(int &, int&); //< 使用Swap模板显示地生成int类型函数定义 显示实例化
template<> void Swap<job>(job& j1, job& j2);//< 显示具体化,特化Swap模板
//< or
//template<> void Swap(job& j1, job& j2);//< 显示具体化,特化Swap模板
void Swap(float c1, float c2); //< 非模板函数
void main()
{
float a = 0.1; //< 调用非模板函数
float b = 0.2;
Swap(a, b);
cout << "a = " << a << " " << "b = " << b << endl; //< a = 0.1 b = 0.2
char g = 1;
char h = 2;
Swap(g, h); //< 隐式实例化
cout << "g = " << (int)g << " " << "h = " << (int)h << endl; //< g = 2 h =1
int i = 10;
int j = 20;
Swap(i, j); //< 显示实例化
cout << "i = " << i << " " << "j = " << j << endl; //< i = 20 j = 10
job sue = { "susan",7300,7 };
job sidney = { "sidney",7800,5 };
Swap(sue, sidney); //< 使用显示具体化
show(sue); //< susan:$7800 on floor:5
show(sidney); //< sidey:$7300 on floor:7
cin.get();
}
void Swap(float c1, float c2)//< 非模板函数
{
return;
}
template <typename T>
void Swap(T& a, T& b) //常规模板
{
T tem;
tem = a;
a = b;
b = tem;
}
template<> void Swap<job>(job& j1, job& j2) //< 显示具体化
{
double t1;
int t2;
t1 = j1.salary;
j1.salary = j2.salary;
j2.salary = t1;
t2 = j1.floor;
j1.floor = j2.floor;
j2.floor = t2;
//< 此处只交换了j1与j2的一部分
}
void show(job& j)
{
cout << j.name << ":$" << j.salary<<" "
<< "on floor:" << j.floor << endl;
}