目录
一.泛型编程
二.函数模板
1.函数模板格式
2.函数模板原理
3.函数模板的实例化
4.模板参数匹配规则
三.类模板
1.类模板的定义格式
2.类模板的实例化
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
模板就是给编译器一个模子,然后让编译器根据不同类型利用这个模子生成对应的代码。
实现一个通用的交换函数可以用函数重载,但是随着数据类型的增多也会变得很麻烦,所以就可以用模板来自动推导数据类型生成对应的交换代码。
函数模板的关键字是template,以下是函数模板的使用格式:
template 返回值类型 函数名(参数列表){}
using namespace std;
template//class是定义模板参数的关键字,也可以用typename
void Swap(T& left, T& right)//T就是根据外部传进来的数据自动推导的
{
T temp = left;
left = right;
right = temp;
}
int main()
{
int i = 0, j = 1;
Swap(i, j);
cout << i << " " << j << endl;//输出 1 0
return 0;
}
函数模板并不是函数,编译器会根据函数接收的数据类型来产生对应数据类型的函数。
比如传进来的是int类型的数据,编译器就会根据Swap模板生成一份T是int的函数来调用实现交换功能。
函数模板的实例化就是用不同数据类型的参数去使用函数模板。实例化分为隐式实例化和显示实例化。
#include
using namespace std;
template//class是定义模板参数的关键字,也可以用typename
T Add(const T& left, const T& right)//T就是根据外部传进来的数据自动推导的
{
return left + right;
}
int main()
{
int i = 0, j = 1;
Add(i, j);//隐式实例化,让编译器自己根据传入数据的类型推导模板参数实际类型
Add(i, j);//指定T参数类型,显示实例化
return 0;
}
如果传两个不同类型就会报错。
#include
using namespace std;
template//class是定义模板参数的关键字,也可以用typename
T Add(const T& left, const T& right)//T就是根据外部传进来的数据自动推导的
{
return left + right;
}
int main()
{
int i1 = 1, i2 = 2;
double d1 = 1.1, d2 = 2.2;
Add(i1, d1);//编译报错:有两种类型,int和double编译器不知道模板参数T应该是int还是double
return 0;
}
解决方法:隐式实例化/显示实例化(如果采用两个模板参数不好确定返回值的类型)
#include
using namespace std;
template//class是定义模板参数的关键字,也可以用typename
T Add(const T& left, const T& right)//T就是根据外部传进来的数据自动推导的
{
return left + right;
}
int main()
{
int i1 = 1, i2 = 2;
double d1 = 1.1, d2 = 2.2;
Add((double)i1, d1);//隐式实例化,让编译器自己根据传入数据的类型推导模板参数实际类型
Add(i1, d1);//指定T参数类型,显示实例化
return 0;
}
模板参数可以和同名函数存在,而且模板参数还可以实例化成这个同名函数。
// 专门处理int的加法函数
int Add(int left, int right)
{
return left + right;
}
// 通用加法函数
template
T Add(T left, T right)
{
return left + right;
}
void Test()
{
Add(1, 2); // 与非模板函数匹配,编译器不需要特化
Add(1, 2); // 调用编译器特化的Add版本
}
对于上面代码的同名函数和模板函数,如果其他条件相同,调用时会优先使用同名函数而不会再实例化出和同名函数一样的函数,如果模板能实例化一个更好的函数,那么会调用模板实例化的函数。
// 专门处理int的加法函数
int Add(int left, int right)
{
return left + right;
}
// 通用加法函数
template
T1 Add(T1 left, T2 right)
{
return left + right;
}
void Test()
{
Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化
Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}
注意:模板函数不允许自动类型转换,但普通函数可以进行自动类型转换!
template
class 类模板名{// 类内成员定义};注意: 类模板中函数放在类外进行定义时,需要加模板参数列表!
template
class A
{
A(T a);//声明
private:
T _a1 = 1;
};
template//类外定义用模板参数要加模板参数列表
A::A(T a)//类外定义,A是类型
{
_a1 = a;
}
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。
// Vector类名,Vector才是类型
Vector s1;//类模板实例化
Vector s2;