范型编程
让编译器更具不同类型利用该模型生成代码(更具体类型无关的代码)
函数模板
template<typename T1,typename T2,........,typename Tn>
cpp
#include <iostream>
template<typename T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
int main()
{
int a=0, b=1;
std::cout << "a:" << a << " b:" << b<<std::endl;
Swap(a, b);
std::cout << "a:" << a << " b:" << b;
return 0;
}
typename时用来定义模板参数关键字的,也可以使用class(但是不能使用struct)
函数模板的原理
函数模板时一个蓝图,它本身不是函数,时编译器用使用方式产生特定类型函数的磨具。所以其实模板就是将本来应该做的重复的事情交给了编译器(也就是函数的重载)
隐式实例化:让编译器根据实参推演参数的实际模板(也就是上面的这种),但是如果有两个参数,编译器无法确定参数实例化
必须采用这两种办法:
- 使用显式实例化
- 用户自己来强制转化
cpp
#include <iostream>
template<typename T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a = 1;
double b = 2.5;
int fault = Add(a,b);//编译器无法确定把T实例化成int还是double
int c = Add<int>(a, b);//1.使用显式实例化
double d = Add((double)a, b);//2.用户自己来强制转化
std::cout << "c:" << c<<" d:"<<d;
return 0;
}
函数模板的匹配原则
- 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化成这个非模板函数
- 对于非模板函数和同名函数模板,如果其他条件相同,在调用时会优先调用非模板函数。如果模板可以产生一个更匹配的函数,那么选择模板
- 模板函数不允许自动类型转换,到那时普通函数可以
cpp
int Add(const int& left, const int& right)
{
return left + right;
}
template<typename T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a = 1;
int b = 2.5;
int c = Add(a, b); //和非模板函数匹配,编译器不需要特化
int d = Add<int>(a, b); //调用编译器特化的Add版本
Add(1, 1);//和非模板函数完全匹配,使用非模板函数
Add(1, 2.5);//模板函数可以生成更加匹配的函数,编译器更具参数生成
std::cout << "c:" << c;
return 0;
}
类模板
类实例化不同类型,类名<数据类型>才是整个类的类型
cpp
template <class T>
class Vector
{
public:
Vector(size_t cap)
:_p(new T [cap])
,_size(0)
,_cap(cap)
{}
~Vector();//类内定义,类外定义
private:
T* _p;
size_t _size;//有限元素个数
size_t _cap;//容量
};
template <class T>
Vector<T>::~Vector()
{
if (_p)
delete[]_p;
_size = _cap = 0;
}
int main()
{
Vector<int> vv(9);
return 0;
}