1. 何为模版?
模板(Templates)分为函数模版和类模版。模版使得我们可以生成通用的函数或类,这些函数或类能够接受任意数据类型的参数,可返回任意类型的值,而不需要对所有可能的数据类型进行函数重载。这在一定程度上实现了宏(macro)的作用。
2. 函数模版:
原型定义可以是下面两种中的任何一个:
template <class identifier> function_declaration;
template <typename identifier> function_declaration;
上面两种原型定义的不同之处在关键字class 或 typename的使用。它们实际是完全等价的,因为两种表达的意思和执行都一模一样。
举例,生成一个函数模版,返回两个数中较大的一个(入参可以为int, 可以为long)
#include <iostream.h>
template <class T> T GetMax (T a, T b) {
T result;
result = (a>b)? a : b;
return (result);
}
int main () {
int i=5, j=6, k;
long l=10, m=5, n;
k=GetMax(i,j); /* 这种模版,参数必须为同种类型 */
n=GetMax(l,m);
cout << k << endl;
cout << n << endl;
return 0;
}
执行结果:
6
10
参数为不同类型的模版:
template <class T>
T GetMin (T a, U b) { return (a<b?a:b); }
在这个例子中,我们的模板函数 GetMin() 接受两个不同类型的参数,并返回一个与第一个参数同类型的对象。在这种定义下,我们可以这样调用该函数:
int i,j;
long l;
i = GetMin <int, long> (j,l);
或者,简单的用
i = GetMin (j,l);
3. 类模版:
类模板(class templates)使得一个类可以有基于通用类型的成员,而不需要在类生成的时候定义具体的数据类型。
下面的例子展示模版类的用法,需要注意的是,如果要在类外定义一个成员函数,必须参照一定的格式,在每个函数前面加上template < ... >。
#include <iostream.h>
template <class T> class pair {
T value1, value2;
public:
pair (T first, T second) {
value1=first;
value2=second;
}
T getmax ();
};
template <class T>
T pair::getmax (){
T retval;
retval = value1>value2? value1 : value2;
return retval;
}
int main () {
pair myobject (100, 75);
cout << myobject.getmax();
return 0;
}
执行结果:
100
4. 模版特殊化:
模板的特殊化是当模板中的pattern有确定的类型时,模板有一个具体的实现。下例是特殊化一个模版,让其中的函数只在对象为int时才工作,其他类型均返回0。
#include <iostream.h>
template <class T> class pair {
T value1, value2;
public:
pair (T first, T second){
value1=first;
value2=second;
}
T module () {return 0;}
};
template <>
class pair <int> {
int value1, value2;
public:
pair (int first, int second){
value1=first;
value2=second;
}
int module ();
};
template <>
int pair<int>::module() {
return value1%value2;
}
int main () {
pair <int> myints (100,75);
pair <float> myfloats (100.0,75.0);
cout << myints.module() << '\n'; /* 25 */
cout << myfloats.module() << '\n'; /* 0 */
return 0;
}
执行结果:
25
0
模板特殊化由以下格式定义:
template <> class class_name <type>
这个特殊化本身也是模板定义的一部分,因此,我们必须在该定义开头写template <>。而且因为它确实为一个具体类型的特殊定义,通用数据类型在这里不能够使用,所以第一对尖括号<> 内必须为空。在类名称后面,我们必须将这个特殊化中使用的具体数据类型写在尖括号<>中。
当我们特殊化模板的一个数据类型的时候,同时还必须重新定义类的所有成员的特殊化实现这样做的原因就是特殊化不会继承通用模板的任何一个成员。
5. 模版的参数:
除了模板参数前面跟关键字class 或 typename 表示一个通用类型外,函数模板和类模板还可以包含其它不是代表一个类型的参数,例如代表一个常数,这些通常是基本数据类型的。
下面是一些模板定义的例子:
template <class T> // 最常用的:一个class 参数。
template <class T, class U> // 两个class 参数。
template <class T, int N> // 一个class 和一个整数。
template <class T = char> // 有一个默认值。
template <int Tfunc (int)> // 参数为一个函数。
6. 模版与函数、类在多文件中的差异:
函数、类的定义可以放在.h中,而实现放在.c中,让接口和实现分离在不同的文件。但是模版于宏功能这种特性,使它的定义与实现必须在同一个文件中。在一个工程中多次包含同时具有声明和实现的模板文件并不会产生链接错误 (linkage errors),因为它们只有在需要时才被编译,而兼容模板的编译器应该已经考虑到这种情况,不会生成重复的代码。