1. 函数模版
1.1 隐式实例化
我们来看下面四个函数,逻辑完全相同,唯一不同的是参数类型,但是逻辑相同能不能写成一个函数呢?
cpp
void Swap(int& a, int& b) {
int tmp = a;
a = b;
b = tmp;
}
void Swap(double& a, double& b) {
double tmp = a;
a = b;
b = tmp;
}
void Swap(char& a, char& b) {
char tmp = a;
a = b;
b = tmp;
}
void Swap(float& a, float& b) {
float tmp = a;
a = b;
b = tmp;
}
这就要引入模版了,我们先自己写个模版
cpp
template<typename T>
void Swap(T& a, T& b) {
T tmp = a;
a = b;
b = tmp;
}
int main() {
int a = 0,b=1;
double c = 1.1, d = 2.2;
Swap(a, b);
Swap(c, d);
return 0;
}
我们看到底层实现是函数重载,也就是说其实调用还是调用像之前我们写的那些函数,不过是编译器帮我们把活干了

模版的推演

库里已经写好了,不需要我们写,我们拿来用就可以了,不过是小写

1.2 显式实例化
上面的是隐式实例化,但有些时候如果只是隐式实例化还不够,举例如下

cpp
template<typename T>
T Add(const T& a, const T& b) {
return a + b;
}
int main() {
int a = 0;
double b = 1.1;
cout << Add(a, (int)b) << endl;
cout << Add((double)a, b) << endl;//我们可以考虑强转
cout << Add<int>(a, b) << endl;
cout << Add<double>(a, b) << endl;//也可以考虑显式实例化,在函数名后加上<参数类型名>
return 0;
}
当然模版可以有多个参数类型
cpp
template<typename T1,typename T2>
T1 Add(const T1& a, const T2& b) {
return a + b;
}
int main() {
int a = 0;
double b = 1.1;
Add<int, double>(a, b);//显示实例化的时候按顺序给类型就可以了
return 0;
}
其实显示实例化主要用于以下不能隐式实例化的情况
cpp
template<typename T>
T* Alloc(int n) {
return T[n];
}
int main() {
Alloc<int>(20);
return 0;
}
2. 类的模版
类的模版和函数模版有些相似,
cpp
template<class T>
class Stack {
public:
Stack(int capacity = 3);
void Push(T& x) {
if (_size == _capacity) {
T* tmp = (T*)realloc(_array, sizeof(T) * _capacity * 2);
if (NULL == tmp) {
perror("realloc fail");
return;
}
_array = tmp;
}
_array[_size++] = x;
}
~Stack() {
if (_array) {
free(_array);
_array = nullptr;
_size = 0;
_capacity = 0;
}
}
private:
T* _array;
int _size;
int _capacity;
};
//但是类存在成员函数声明和定义分离的问题,注意没有模版的情况下,类名和类型名是一致的,但是有了模版,类名是Stack,类型名是Stack<T>,函数在类外定义的情况下,用的是类型名::,同时不要忘记template<typename T>
template<typename T>
Stack<T>::Stack(int capacity) {
_array = new T[capacity];
_size = 0;
_capacity = capacity;
}
int main() {
Stack<double> s1;
Stack<int>* p1 = new Stack<int>;
delete p1;
return 0;
}