目录
关于模板
模板的本质是通过复用来避免重复的工作,一个通过模板通常有个两部分:不变的部分和可变的部分,不可变指的是在复用过程中不可参的部分,可变指的时复用时可参与的部分。
例如,一个用于制作月饼的模板,可参与部分就是它的馅料,不可参与的部分就是它的形状
模板在语言中也是同理,我们只需要写出一个的具体模板然后再根据使用场景填入可变的部分,编译器就会根据模板+可变的部分自动的推导出模板函数或模板类;
C++有两种类型的模板:函数模板和类模板,模板中不可变的部分是代码逻辑,可变的部分是变量类型。
函数模板
介绍
函数模板是一种C++的语言特性,用于定义通用的函数以实现代码的重用性和灵活性。大致过程是:定义一个函数模板,在调用时编译器会根据你给的类型结合函数模板,生成对应模板函数,而我们调用使用的就是这个模板函数,换句话说编译器会根据(函数模板+我们给的类型)生成对应的模板函数。
定义方式是:关键字typename后跟尖括号,尖括号里面是函数模板的参数(用typename 或class定义),用作类型占位符在函数模板实例化时替换成对应的类型。typename定义在函数上方。
template <typename T1, class T2>
返回类型 函数名(参数列表)
{
// 函数体
}
函数模板推导模板函数过程
函数模板的实例化
函数模板的实例化是指在编译过程中,根据实际使用的类型参数生成对应模板函数的过程,有两种方式可以实例出模板函数,隐式实例化与显示实例化。
隐式实例化:让编译器根据实参去推演模板参数的实际类型
//函数模板
template<typename T1, typename T2>
void function(T1 left, T2 right)
{
;
}
//对应模板函数
void function(int left, double right)
{
;
}
int main()
{
function(20,3.14);
return 0;
}
显式实例化:在函数名后的<>中指定模板参数的实际类型
//函数模板
template<typename T1, typename T2>
void function(T1 left, T2 right)
{
;
}
//对应模板函数
void function(int left, double right)
{
;
}
int main()
{
function<int,double>(20,3.14);
return 0;
}
函数模板的特点
- 函数模板的模板参数在推导时不能有歧义
template<typename T>
void function(T left, T right) //编译报错,T到底是int还是double?
{
;
}
int main()
{
function(20,3.14);
return 0;
}
- 函数模板的模板参数必须要全部推导出类型
template<typename T1, typename T2, typename T3>
void function(T1 left, T2 right) //编译报错,无法推出T3的类型
{
;
}
int main()
{
function(20,3.14);
return 0;
}
- 函数模板的模板参数可以给缺省值
- 函数模板的参数可以有多个
- 一个模板只能产生一个函数模板
- 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数
template<typename T1, typename T2>
void function(T1 left, T2 right)
{
printf("1");
}
void function(int left, double right)
{
printf("2");
}
int main()
{
function<int,double>(20,3.14); //可以同时存在
return 0;
}
类模板
定义
template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
特类模板与函数模板不同的地方在于,在我们创建类对象时就已经发生了模板的实例化,所以无法隐式实例化只能显示实例化。
Vector<int> s1;
Vector<double> s2;
特性
- 类模板并不是类就如同函数模板不是函数一样,从类模板到对象的顺序是:先通过类模板实例化出模板类在通过模板类实例化出对象。
- 如果类的成员函数定义在外面的话,需要在该函数上面加上模板提示,并且在声明类域时加上<模板参数>。
template<class T >
class A
{
public:
void print(T d = 20);
private:
int _a = 10;
};
//类成员定义在类外面
template<class T >
void A<T>::print(T d)
{
std::cout << _a << d << "\n";
}