1、一些基础知识点
(1)类名的使用与类类型的使用区分
定义一个模板Stack,如何区别使用Stack 与Stack
template<typename T>
class Stack {
private:
std::vector<T> elems; // 储存元素的数量
public:
Stack(); // 构造函数,不是Stack<T>
...
};
这个类的类型是Stack,当声明中需要使用该类的类型时,必须使用Stack,但是如果使用的是类名,而不是类型,就应该只用Stack,如构造函数、析构函数等。
(2)类模板使用的时候,必须显示的指定模板实参,如vector 必须显示指定模板实参类型为int
(3)对于类模板,只有哪些被调用的成员函数,才会产生这些函数的实例化代码
优点主要有两点:节省空间和时间 另外,对于某些类型,不能提供所有成员操作,仍然可以使用该类型来实例化模板,
只要不调用那些不支持的操作就行(不调用也就不会实例化相应的成员函数)
template<typename T>
class Stack {
private:
std::vector<T> elems; // 储存元素的数量
public:
Stack(); // 构造函数,不是Stack<T>
T accumulate(); // 该函数的作用是,将vector中所有元素求和
...
};
在上面的类模板中,成员函数accumulte的作用是对vector中的元素求和,如果类模板参数T是普通的int 等类型是可以求和的,但是如果T是一个类类型C,显然是不能对类型C求和的,但是仍然可以使用C实例化这个类,只要不调用函数accumulate,那么在实例化的时候,就不会实例化函数accumulate,就能顺利通过编译。
(4)类模板可以特化,特化一定要加上template<> 里面参数列表可以为空也可以不为空
(5)类模板支持缺省模板实参,并且后面的模板参数可以应用前面的模板参数
如:
template<tyename T, typename CONT = std::vector>
2、非类型模板参数
模板参数并不局限于类型,普通值也可以作为模板参数。
template<typename T, int MaxSize> // MaxSize 为非类型模板参数
class Stack
{
private:
T elems[MaxSize]; // 用来指定数组的大小
...
};
同样可以为非类型参数添加缺省值
template<typename T, int MaxSize = 1024> // 指定缺省大小为1024
class Stack
{
private:
T elems[MaxSize]; // 用来指定数组的大小
...
};
函数模板也可以添加非类型模板参数
非类型模板参数的限制,通常而言,它们可以是常整数(包括枚举值),或是指向外部链接对象的指针,浮点数和类对象是不允许作为非类型模板参数的
3、技巧性基础知识
(1)typename关键字
关键字typename ,引入关键字是为了说明模板内部的标识符可以是一个类型
template<typename T>
class MyClass{
typename T::Subtype *ptr;
...
};
如果不使用typename , Subtype 就会被认为是一个静态成员,那么它就应该是一个具体的对象或者变量,于是下面的表达式:
T::Subtype * ptr, 就会被看做是类T的静态成员Subtype 与 ptr的乘积。即解释为 (T::Subtype) * ptr
(2)使用this关键字
对于具有基类的类模板,自身使用名称x并不一定等同于this->x,即使该x是从基类继承获得的,也是如此。例如:
template<typename T>
class Base{
public:
void exit();
};
template<typename T>
class Drived : Base<T>
{
public:
void foo()
{
exit(); // 这里只会调用外部的exit()或者出现错误,并不会调用基类的exit()
}
...
};
对于那些在基类中声明,并且依赖模板参数的符号(函数或者变量),你应该在他们前面使用this-> 或者 Base:: 来限定访问的成员
(3)成员模板
类的成员函数也可以是模板
template<typename T>
class Stack {
public:
// 使用元素类型为T2的栈进行赋值
template<typename T2>
Stack<T>& operator= (Stack<T2> const &);
...
};
// 类外进行定义时,格式如下:
template<typename T>
template<typename T2>
Stack<T> & Stack<T>::operator= (Stack<T2> const & op2)
{
// ....
};
4、模板的模板参数
有时候,让模板本身成为模板是很有用的,如:
template<typename T, template<typename ELEM> class CONT = std::deque >
class Stack {
private:
CONT<T> elems; //保存元素的容器
public:
...
};
不同之处在于,第二个模板参数被声明为一个类模板。同时由于并不会用到上面的”模板的模板参数“的模板参数,即ELEM
因此,可以把该名称省略。
template<typename T, template class CONT = std::deque >
class Stack {
private:
CONT elems; //保存元素的容器
public:
…
};
需要说明的是:函数模板并不支持,模板的模板参数