19-实例化和具体化
8.5.4 实例化和具体化
为进一步了解模板,必须理解术语实例化和具体化。记住,在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。编译器使用模板为特定类型生成函数定义时,得到的是模板实例(instantiation)。例如,在程序清单8.13中,函数调用Swap(i, j)导致编译器生成Swap()的一个实例,该实例使用int类型。模板并非函数定义,但使用int的模板实例是函数定义。这种实例化方式被称为隐式实例化(implicit instantiation),因为编译器之所以知道需要进行定义,是由于程序调用Swap()函数时提供了int参数。
最初,编译器只能通过隐式实例化,来使用模板生成函数定义,但现在C++还允许显式实例化(explicit instantiation)。这意味着可以直接命令编译器创建特定的实例,如Swap
template void Swap<int>(int, int); // explicit instantiation
实现了这种特性的编译器看到上述声明后,将使用Swap()模板生成一个使用int类型的实例。也就是说,该声明的意思是“使用Swap()模板生成int类型的函数定义。”
与显式实例化不同的是,显式具体化使用下面两个等价的声明之一:
template <> void Swap<int>(int &, int &); // explicit specialization
template <> void Swap(int &, int &); // explicit specialization
区别在于,这些声明的意思是“不要使用Swap()模板来生成函数定义,而应使用专门为int类型显式地定义的函数定义”。这些原型必须有自己的函数定义。显式具体化声明在关键字template后包含<>,而显式实例化没有。
警告: 试图在同一个文件(或转换单元)中使用同一种类型的显式实例和显式具体化将出错。
还可通过在程序中使用函数来创建显式实例化。例如,请看下面的代码:
template <class T>
T Add(T a, T b) // pass by value
{
return a + b;
}
...
int m = 6;
double x = 10.2;
cout << Add<double>(x, m) << endl; // explicit instantiation
这里的模板与函数调用Add(x, m)不匹配,因为该模板要求两个函数参数的类型相同。但通过使用Add
如果对Swap()做类似的处理,结果将如何呢?
int m = 5;
double x = 14.3;
Swap<double>(m, x); // almost works
这将为类型double生成一个显式实例化。不幸的是,这些代码不管用,因为第一个形参的类型为double &,不能指向int变量m。
隐式实例化、显式实例化和显式具体化统称为具体化(specialization)。它们的相同之处在于,它们表示的都是使用具体类型的函数定义,而不是通用描述。
引入显式实例化后,必须使用新的语法——在声明中使用前缀template和template <>,以区分显式实例化和显式具体化。通常,功能越多,语法规则也越多。下面的代码片段总结了这些概念:
...
template <class T>
void Swap (T &, T &); // template prototype
template <> void Swap<job>(job &, job &); // explicit specialization for job
int main(void)
{
template void Swap<char>(char &, char &); // explicit instantiation for char
short a, b;
...
Swap(a,b); // implicit template instantiation for short
job n, m;
...
Swap(n, m); // use explicit specialization for job
char g, h;
...
Swap(g, h); // use explicit template instantiation for char
...
}
编译器看到char的显式实例化后,将使用模板定义来生成Swap()的char版本。对于其他Swap()调用,编译器根据函数调用中实际使用的参数,生成相应的版本。例如,当编译器看到函数调用Swap(a, b)后,将生成Swap()的short版本,因为两个参数的类型都是short。当编译器看到Swap(n, m)后,将使用为job类型提供的独立定义(显式具体化)。当编译器看到Swap(g, h)后,将使用处理显式实例化时生成的模板具体化。