前言
函数模板是函数的抽象,它与普通函数相似,唯一的区别就是函数参数的类型是不确定的,函数参数的类型只有在调用过程中才被确定。
这里简单记录一下方便自己查阅和回顾。
主要涉及typename,template,class等关键字
正文
函数模板
函数模板语法格式:
template<typename 类型占位符> 返回值类型 函数名(参数列表) { //函数体; }
template是声明模板的关键字,<>中的参数称为模板参数
template<typename T> T Add(T a) { return ++a; }
typename关键字用于标识模板参数,可以用class关键字代替typename,class和typename并没有区别
template<class T> T Add(T a) { return ++a; }
模板参数不能为空,一个函数模板中可以有多个模板参数,模板参数和普通函数参数相似。
template<typename type> type Max(type a, type b) { if (a > b) { return a; } else { return b; } }
type表示数据类型,比如可以为int,float,double等,这样就不必创建太多类型的函数了。
这里以Max模板函数为例。
// int int max = Max(100, 200); std::cout << max << std::endl; // float float maxFloat = Max(100.1f, 808.0f); std::cout << maxFloat << std::endl;
上面使用< double >和< float >就是防止类型转换,表示强制性类型为<>内的。
函数模板并不是一个函数,它相当于一个模子,定义一次即可使用不同类型的参数来调用该函数模板,这样做可以减少代码的书写,提高代码的复用性和效率。
隐式实例化
隐式实例化是根据函数调用时传入的参数的数据类型确定模板参数T的类型,模板参数的类型是隐式确定的。
int max = Max(100, 200); float maxFloat = Max(100.1f, 808.0f);
这种就是隐式实例化。默认分别为int和float。
但是,这种隐式实例化方式有个不好的地方,比如第二个参数传入为不带.f的(会被识别出为int类型),编译器就有有提示:没有与参数列表匹配的 重载函数 实例参数类型为: (float, int)
// 下面写法无法通过编译 //float maxFloat = Max(100.1f, 808);
显式实例化
隐式实例化有上面问题,因此就出现显式实例化的方式。
以上面为了,改为如下后就可以正常编译。
float maxFloat = Max<float>(100.1f, 808); float maxFloat = Max<float>(100.1, 808);
模板函数重载
这个跟函数重载一样的道理。相同的函数名,参数类型或参数个数不一样。
下面只是简单展示,具体可以看函数重载那部分。
template<typename type> type Max(type a, type b) { if (a > b) { return a; } else { return b; } } template<typename type> type Max(type a, type b, type c) { if (a > b ) { if (a > c) { return a; } else { return c; } } else { if (b > c) { return b; } else { return c; } } }
只是随便写一下,具体参考函数重载来看。
注意事项
<>中的每一个类型参数在函数模板参数列表中必须至少使用一次
#include <iostream> template<typename type1, typename type2> type1 Max(type1 a, type1 b) { if (a > b) { return a; } else { return b; } } int main() { int max = Max<int,double>(100, 200); std::cout << max << std::endl; return 0; }
上面只使用了type1,不过,使用时需要使用显示实例化。
全局作用域中声明的与模板参数同名的对象、函数或类型,在函数模板中将被隐藏。
int num = 201; template<typename T> void func(T t) { T num = t; std::cout << num << std::endl; //输出的是局部变量num,全局int类型的num被屏蔽 }
在函数体内访问的num是T类型的变量num,而不是全局int类型的变量num。
函数模板中声明的对象或类型不能与模板参数同名。
template<typename T> void func(T t) { //错误,定义的类型与模板参数名相同 typedef float T; T number = 100.0f; std::cout << number << std::endl; }
我这VS可以编译过,也没有报错,但这种写法很容忍费解。。。。
不推荐这种写法!!!
模板参数名在同一模板参数列表中只能使用一次,但可在多个函数模板声明或定义之间重复使用。
template<typename type, typename type> type Max(type a, type b) { //略 }
上面错误,定义了两个type参数,这这个不能相同,下面的OK
template<typename type1, typename type2> type1 Max(type1 a, type2 b) { //略 }
如果函数模板有多个模板参数,则每个模板参数前都必须使用关键字class或typename修饰。
下面是错误的
template<typename type1, type2> type1 Max(type1 a, type2 b) { //略 }
正确的。typename或class不可省略。
template<typename type1, typename type2> type1 Max(type1 a, type2 b) { //略 }