实例化与具体化是两个不同概念术语。
首先应该明确,在代码中包含函数模板本身并不会生成函数定义,它只是一个用于生成函数定义的方案。
编译器使用模板为特定类型生成函数定义时,得到的是模板实例(instantiation)。例如,有下面的模板定义:- template <class T> // 模板
- void Swap(T &, T &);
复制代码 当函数调用 Swap(i, j) 时( i 和 j 为 int 类型),将导致编译器生成 Swap() 的一个实例。模板并非函数定义,但使用 int 的模板实例是函数定义。这种实例化方式被称为隐式实例化(implicit instantiation)。
C++ 不但可以隐式实例化,还允许显式实例化(explicit instantiation)。这意味着,可以直接命令编译器创建特定的实例,如 Swap<int>() 。其语法是,声明所需的种类 --- 用 <> 符号指示类型,并在声明前加上关键字 template :- template void Swap<int>(int, int); //显式实例化
复制代码 该声明的意思是,使用 Swap() 模板生成 int 类型的函数定义。
与显式实例化不同的是,显式具体化使用下面两个等价的声明之一:- template <> void Swap<int> (int &, int &); // 显式具体化
- template <> void Swap(int &, int &); // 显式具体化
复制代码 区别在于:这些声明的意思是“不要使用 Swap() 模板来生成函数定义,而应使用专门为 int 类型显式地定义的函数定义。” 这些原型必须有自己的函数定义。显式具体化声明在关键字 template 后包含 <>,而显式实例化没有。
注意:试图在同一个文件(或转换单元)中使用同一种类型的显式实例和显式具体化将出错。
还可以通过在程序中使用函数来创建显式实例化:- template <class T>
- T Add(T a, T b)
- {
- return a + b;
- }
- int m = 6;
- double x = 10.2;
- cout << Add<double>(x, m) << endl; //显式实例化
复制代码 这里的模板与函数调用 Add(x, m) 不匹配,因为该模板要求两个参数的类型要相同。但通过使用 Add<double>(x, m),可强制为 double 类型实例化,并将参数 m 强制转换为 double 类型,以便与函数 Add<double>(double, double) 的第 2个参数匹配。
隐式实例化、显式实例化和显式具体化统称为具体化( specialization )。它们的相同之处在于,它们表示的都是使用具体类型的函数定义,而不是通用描述。
引入显式实例化后,必须使用新的语法 --- 在声明中使用前缀 template 和 template<> ,以区分显式实例化和显式具体化。
下面的代码片段总结了这些概念:
[C++] 纯文本查看 复制代码 ...
template <class T>
void Swap (T &, T &); // 模板原型
template <> void Swap<job>(job &, job &); // 对 job 的显式具体化
int main(void)
{
template void Swap<char>(char &, char &); // 对 char 的显式实例化
short a, b;
...
Swap(a,b); // 对 short 的隐式实例化
job n, m;
...
Swap(n, m); // 对 job 使用显式具体化
char g, h;
...
Swap(g, h); // 对 char 使用显式实例化
...
}
编译器看到 char 的显式实例化后,将使用模板定义来生成 Swap() 的 char 版本。对于其他 Swap() 调用,编译器根据函数调用中的实际使用参数,生成相应的版本。例如,当编译器看到函数调用 Swap(a, b) 后,将生成 Swap() 的 short 版本,因为这两个参数的类型都是 short 。当编译器看到 Swap(n, m) 后,将使用为 job 类型提供的独立定义(显式具体化)。当编译器看到 Swap(g, h) 后,将使用处理显式实例化时生成的模板具体化。
|