模板可以大致分为两类。一是函数模板,还有类模板。
一.函数模板
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生 函数的特定类型版本。这是函数模板的概念。
下面举一个Swap的一个例子。
template<typename T>
void Swap( T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
注意既可以用typename也可以用class,这就说这样也行。
template<class T>
void Swap( T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
函数模板的使用也是更普通函数差不多的。
template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20,a = 30;
double d1 = 10.0, d2 = 20.0,d = 30.0;
//推导实例化
Add(a1, a2);
Add(d1, d2);
/*
该语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型
通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有
一个T,
编译器无法确定此处到底该将T确定为int 或者 double类型而报错
注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要
背黑锅
Add(a1, d1);
*/
// 此时有两种处理方式:1. 用户自己来强制转化 2. 使用显式实例化
//自己强转
Add(a, (int)d);
// 显式实例化
Add<int>(a, d);
return 0;
}
二.类模板
我们直接来看一个例子。
#include<iostream>
using namespace std;
// 类模版
template<typename T>
class Stack
{
public:
Stack(size_t capacity = 4)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}
void Push(const T& data);
private:
T* _array;
size_t _capacity;
size_t _size;
};
template<class T>
void Stack<T>::Push(const T& data)
{
// 扩容
_array[_size] = data;
++_size;
}
int main()
{
Stack<int> st1; // int
Stack<double> st2; // double
return 0;
}
函数模板和类模板只有被调用或使用是才能实例化,此时编译器会自动生成相应的函数或类以供使用。