什么是函数模板
函数模板是模板的一种,区别于类的地方只是它修饰的是函数,而类模板修饰的是类。
函数模板出现的目的是为了让程序员可以编写和类型无关的代码。也就是说编写一个函数可以多种类型的参数通用。
函数模板的格式
template <typename 形参名,typename 形参名,...>
返回类型 函数名(参数列表)
{
//函数体
}
- template 和typename 是关键字,其中typename也可以用class替换,使用中并没有什么区别
- <>内跟的是模板的参数,而且这些参数可以不止一个
- 在调用模板函数时模板参数是可以自动推导的,所以有的时候可不写,具体见下文
函数参数的推导
#include <iostream>
using namespace std;
template<typename T1,typename T2>
int maxSize(T1 num1, T2 num2)
{
return sizeof(num1) > sizeof(num2) ? sizeof(num1) : sizeof(num2);
}
int main()
{
//完整写法
cout << maxSize<int, double>(1, 2.0) << endl;
//自动推导模板参数
cout << maxSize('a',1) << endl;;
return 0;
system("pause");
}
运行结果
可以看出,我即使不写出模板参数<char,int>
第二次调用仍然成功了,这其中就是模板参数的自动推导起了作用。
注意:并不是所有的模板函数调用时都可以进行模板参数推导的
必须满足以下条件才可以:
1、模板的形参必须与模板函数的形参在位置上存在一一对应的关系
2、要推导的模板参数必须是连续且位于参数列表末尾的,这一点和给函数形参赋默认值差不多
3、编译器只根据函数调用时给出的实参列表来推导模板参数值,与函数参数类型无关的模板 参数其值无法推导。
4、与函数返回值相关的模板参数其值也无法推导。
模板和宏的区别
- 宏是预编译时替换,模板是编译时生成·。
- 它们两者的区别在于模板是有函数检查的,而宏没有这个功能。
模板实例化过程
模板函数的实例化经历两个过程:
1. 检查语法错误
主要在语法层面上进行检查,比如说少了个分号或者缺少}之类的,如果在这个过程中没有通过的话就不能进行正常编译。
2. 检查调用错误·
template <typename T>
const T Max(T lhs, T rhs)
{
return lhs > rhs ? lhs : rhs;
}
class Test{}
int main()
{
Max(1, 2); // OK
Test t1, t2;
Max(t1, t2);
return 0;
}
错误信息:
严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2784 “bool std::operator >(const std::basic_string<_Elem,_Traits,_Alloc> &,const _Elem *)”
:可以看出这里并没有对类Test进行大于号‘>’重载,而在调用模板函数时传入的实参是Test类型,且在内部使用大于号进行了比较所以检查出来了错误。
模板函数和重载函数比较
这里说的重载函数只是普通的重载函数,并不包括模板函数的重载(没错,模板函数也是能重载的,除了不能提升转换,重载的条件和普通函数重载一样。)
1. 重载函数和模板函数根据参数的不同都会生成不同的函数。
#include <iostream>
template<typename T1, typename T2>
void maxSize(T1 num1, T2 num2){}
int main()
{
maxSize(1, 2.0);
maxSize('c', 1);
return 0;
system("pause");
}
可以看出在内存中生成的两个maxSize()函数是占有不同的内存空间的,这一点和重载函数一模一样。
2. 所有的重载函数在编译阶段都会在内存中生成而模板函数则是什么时候调用什么时候生成。