1.函数模板
代表一个函数,但不是函数,只是一个模板,与类型无关,在使用时被参数化,才成为函数,typename是用来定义模板的参数关键字,用class也可以,但是没有struct
template <class\typename T1, class\typename T2, class\typename T3,...>
返回值 函数名(参数)
{
...
}
如果参数模板接收到了多个类型,有三种方法:
int a = 1;
double d = 10.1;
1.强制类型转换
Add(a, (int)d);
Add((double)a, d);
2.显示实例化
Add<int>(a, d);
Add<double>(a, d);
3.在函数模板处,用auto作为返回值,让编译器自己判断
template<class T1, class T2>
auto Add(T1& left, T2& right)
{ ... }
显示实例化的其他场景:
T* func(int* a)
{
...
}
int* ret = func<int>(1);
因为参数里没有模板类型,只在返回值里面,所以要显示说明一下
函数模板的匹配规则:
1.一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数,如果没有特殊说明就调用非函数模板
//专门处理int的非模板加法函数
int Add(int left, int right)
{
return left + right;
}
//模板加法函数
template<class T>
T Add(T left, T right)
{
return left + right;
}
void Test()
{
Add(1, 2); //与非模板函数匹配,直接调用
Add<int>(1, 2); //调用编译器特化的模板Add版本
}
2.对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板
//专门处理int的非模板加法函数
int Add(int left, int right)
{
return left + right;
}
//模板加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{
return left + right;
}
void Test()
{
Add(1, 2); //与非函数模板类型完全匹配,不需要函数模板实例化
Add(1, 2.0); //模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}
2.类模板
类的模板,也是在类的定义之前加template声明
template<class T1, class T2, class T3, ... >
class 类模板名
{
...
};
类模板的实例化:
template <class T>
class A { ... };
A是类名,A<int>才是类型,要把具体类型确定才可以实例化
A<int> a1;
A<double> a2;
类模板内函数放在类外定义时,需要加模板参数列表
template <class T>
class A
{
public:
void test();
...
};
template <class T>
A<T>::void test()
{
...
}
3.模板类
模板类是由类模板实例化创建的类
区分:类模板是模板,模板类是类