CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

C++模版:深入使用函数模版-源码交易平台丞旭猿

上文函数模版初探介绍了函数模版的基本使用,本文深入探讨函数模版。

函数模版参数的类型转换

函数模版有多个同类型的形参,使用过程中会碰到类型转换问题。

下面是一个加法函数模版:

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转换为intfloat转换为double
  • 标准转换,比如char转换为floatint转换为charlong转换为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);}

下面情况都是完全匹配,输出结果如下:

  • 使用145,则编译器选择普通函数1,输出日志eat(int a)
  • 使用45,则编译器选择显示具体化函数5,输出日志template void eat(int a)

下面情况是完全匹配优先级高于提升转换或者标准转换,输出结果如下:

  • 使用234,则编译器选择函数模版4,输出日志template void eat(T a)

测试用例2:

voidtest5(){chara=a;eat(a);}

下面情况是提升转换优先级高于标准转换,输出结果如下:

  • 使用13,则编译器选择提升转换1,输出日志eat(int a)

总结

  • 使用函数模版,要注意隐式类型转换
  • 函数模版支持重载
  • 函数模版不能处理所有的类型,可以为特定类型提供具体化的函数定义
  • 如果多个函数或者模版符合要求,编译器会根据优先级,选择最合适的函数

请大家多多关注

,带来更多计算机相关知识。

点击下方卡片阅读原文

声明:本文部分素材转载自互联网,如有侵权立即删除 。

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
相关推荐
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容