上文函数模版初探介绍了函数模版的基本使用,本文深入探讨函数模版。
函数模版参数的类型转换
函数模版有多个同类型的形参,使用过程中会碰到类型转换问题。
下面是一个加法函数模版:
template<typenameT>Tadd2(Ta,Tb){std::cout<<"T add2(T a, T b)"<<std::endl;returna+b;}
使用隐式实例化,2个实参的类型必须相同,否则编译出错No matching function for call to add
。
使用显示实例化,2个实参的类型可以不同,但是会发生隐式类型转换。
voidtest1(){// 2个实参类型相同,可以使用隐式实例化inta1=1;intb1=2;add2(a1,b1);// 2个实参类型不同,不能使用隐式实例化inta2=1;shortb2=1;// No matching function for call to add2// add2(a2, b2);// 显示实例化, short被隐式转换成intadd2<int>(a2,b2);}
函数模版重载
函数模版跟普通函数一样支持重载。函数参数列表中,参数不一定是泛型,也可以是具体的类型。
比如,加法函数模版中,增加3个数相加的函数模版。第3个参数,可以是泛型,也可以是具体的double
类型。
template<typenameT>Tadd2(Ta,Tb,Tc){std::cout<<"T add2(T a, T b, T c)"<<std::endl;returna+b+c;}template<typenameT>Tadd2(Ta,Tb,doublec){std::cout<<"T add2(T a, T b, double c)"<<std::endl;returna+b+c;}
函数模版的局限性及解决方案
函数模版很可能无法处理某些类型。
比如下面的例子,如果T
是自定义类FTPerson
,则无法正常运行。
template<typenameT>boolequal(T&a,T&b){returna==b;}classFTPerson{public:intage;};
一种解决方案是,为特定类型提供具体化的函数定义,这称之为显示具体化(explicit specialization
)。
显示具体化的原型和定义:
template<>boolequal<FTPerson>(FTPerson&p1,FTPerson&p2);template<>boolequal<FTPerson>(FTPerson&p1,FTPerson&p2){std::cout<<"equal(FTPerson &p1, FTPerson &p2)"<<std::endl;returnp1.age==p2.age;}
编译器会选择最合适的显示具体化函数。
voidtest3(){FTPersonp1;FTPersonp2;equal(p1,p2);// 调用的是具体化函数}
编译器选择哪个函数
调用函数时,如果有多个函数或者模版符合要求:
- 函数名称相同
- 实参与形参个数相同,并且类型相同或者可以隐式转换
编译器必须选择一个最佳的函数。以下匹配规则,优先级从高到低:
- 函数完全匹配,按照下面优先级匹配
- 普通函数
- 模版的显示具体化函数
- 函数模版
- 提升转换,比如
char
转换为int
,float
转换为double
- 标准转换,比如
char
转换为float
,int
转换为char
,long
转换为double
下面是5个函数或者模版,编号是1到5。使用不同编号的函数和测试用例,验证匹配规则。
// 1 普通函数voideat(inta){std::cout<<"eat(int a)"<<std::endl;}// 2 普通函数voideat(chara){std::cout<<"eat(char a))"<<std::endl;}// 3 普通函数voideat(floata){std::cout<<"eat(float a)"<<std::endl;}// 4 函数模版template<typenameT>voideat(Ta){std::cout<<"template void eat(T a)"<<std::endl;}// 5 模版的显示具体化函数template<>voideat(inta){std::cout<<"template void eat(int a)"<<std::endl;}
测试用例1:
voidtest4(){inta=1;eat(a);}
下面情况都是完全匹配,输出结果如下:
- 使用
1
,4
,5
,则编译器选择普通函数1
,输出日志eat(int a)
- 使用
4
,5
,则编译器选择显示具体化函数5
,输出日志template void eat(int a)
下面情况是完全匹配优先级高于提升转换或者标准转换,输出结果如下:
- 使用
2
,3
,4
,则编译器选择函数模版4
,输出日志template void eat(T a)
测试用例2:
voidtest5(){chara=a;eat(a);}
下面情况是提升转换优先级高于标准转换,输出结果如下:
- 使用
1
,3
,则编译器选择提升转换1
,输出日志eat(int a)
总结
- 使用函数模版,要注意隐式类型转换
- 函数模版支持重载
- 函数模版不能处理所有的类型,可以为特定类型提供具体化的函数定义
- 如果多个函数或者模版符合要求,编译器会根据优先级,选择最合适的函数
请大家多多关注
,带来更多计算机相关知识。点击下方卡片阅读原文:
声明:本文部分素材转载自互联网,如有侵权立即删除 。
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是赞助,收取费用仅维持本站的日常运营所需!
7. 如遇到加密压缩包,请使用WINRAR解压,如遇到无法解压的请联系管理员!
8. 精力有限,不少源码未能详细测试(解密),不能分辨部分源码是病毒还是误报,所以没有进行任何修改,大家使用前请进行甄别
丞旭猿论坛
暂无评论内容