c++模板全面解析
模板作为c++的一个重要功能,自己对它的使用非常的少,所以决定写一篇文档出来加深自己的记忆。本文是根据c++ primer plus第六版中关于模板的部分写成。
一、引言
在我们实际的使用中有时候难免要对不同的数据类型进行相同的操作,如果我们对每一种数据类型都实现相同的操作,无疑是在重复造轮子,实际意义并不大。c++中的模板为我们解决这个问题提供了一个很好的方法。
模板提供参数化类型,即能够将类型名作为参数传递给接收方来建立类或函数。像c++中的STL就是通过模板来实现的。
二、类模板
1、定义
template<typename T>
class Stack {
private:
enum {MAX = 10};
T items[MAX];
int top;
public:
bool push(const Type& item);
//在类声明中定义了方法(内敛定义),则可以省略模板前缀和类限定符
bool pop(Type & item) {
//ToDo
}
};
bool Stack<Type>::push(const Type& item) {
//ToDo
}
另一种定义
类模板不仅可以是参数类型,也可以是非参数类型。但是模板代码不能修改参数的值,例如n++或&n等表达式。另外实例化模板时,用作表达式参数的值必须是常量表达式。
template <class T, int n>
class ArrayTP {
};
默认类型模板参数
不提供第二个参数时第二个参数默认为int类型
```c++
template <class T, class T = int>
class ArrayTP {
};
2、使用
模板的具体实现被称为实例化或具体化。不能将模板成员函数放在独立的实现文件中。由于模板不是函数他们不能单独编译。模板必须与特定的模板实例化请求一起使用。为此,最简单的方法是将所有模板的信息放在同一个头文件中,并在要使用这些模板的文件中包含该头文件
仅在程序中包含模板并不能生成模板类,而必须请求实例化。为此需要声明一个类型为模板类的对象,方法是使用所需的具体类型替换泛型名。例如,下面的代码创建两个栈,一个用于存储int,一个用于存储string对象
Stack<int> kernels;//基础类型int
Stack<string> colonels;//对象类型string
模板的多功能性
递归使用模板
即模板中嵌套模板
常用的vector<vector>定义一个二位的数组
三、模板的具体化
模板的具体化分为三类。分别是隐式实例化,显示实例化,显示具体化
1、隐式实例化
声明一个对象或多个对象,指出所需的类型,而编译器使用通过模板提供的处方生成具体的类定义。
编译器在需要对象之前不会生成类的隐式实例化
ArrayTP<double, 30> * pt;//一个指针,并没有生成对象
pt = new ArrayTP<double, 30>;//现在才生成对象
2、显示实例化
当使用template关键字并指出所需类型来声明类型时,编译器将生成类声明的显示实例化。声明必须位于模板定义所在的名称空间中。
template class ArrayTP<string, 100>
在这种情况下,虽然没有创建或提及类对象,编译器也将生成类声明。和隐式实例化一样,也将根据通用模板来生成具体化。
3、显示具体化
显示具体化是特定类型的定义。有时候可能需要在为特殊类型实例画、化时,对模板进行修改,使其行为不同。在这种情况下,可以创建显示具体化。
在这种情况下可以提供一个显示模板具体化,这将采用为具体类型定义的模板,而不是为泛型定义的模板。当具体化模板和通用模板都与实例化请求匹配时,编译器将采用具体化的版本。
具体化类模板的定义如下:
template <> class Classname<specialialized-type-name> { ... };
4、部分具体化
c++还允许部分具体化,即部分限制模板的通用性。例如部分具体化可以给类型参数之一制定具体的类型:
//general template
template <class T1, class T2> class Pair { ... };
//specialization with T2 set to int
template <class T1> class Pait <T1, int> { ... };
//specialization with T2 and T1 set to int
template <> class Pair <int, int> { ... };//转换成了显示具体化
如果有多个模板可供选择优先选择具体化程度最高的模板。