news 2026/4/6 19:32:45

函数模板.

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
函数模板.

闲谈:上一篇初识模板我也只是初略了解,这一次我在整理一下。

模板

模板是C++支持泛型程序设计的工具,通过它可以实现参数化多态性。

参数化多态性:就是将程序所处理的对象的类型参数化,使得一段程序可以处理多种不同类型的对象。

函数模板

与重载、宏定义对比所解决的缺陷

重载与函数模板

函数模板与函数重载看起来大同小异,但是重载的类不能传入与之相同类型的参数,从而使得要多建几个代码框架相同的函数,使程序代码冗余,可读性降低。

比如:

int max(int x,int y){…} float max(float x,float y){…}

与之相似的还有宏定义:

宏定义只是在编译时进行简单的宏展开,避开了类型检查机制,容易产生隐藏错误。

#define max(x,y) ((x)>(y)?(x):(y)) max(a++, b++) //替换后:((a++)>(b++)?(a++):(b++))

像这样,我们调用max宏定义替换时,a和b会产生多次自增,而我们需要的只是一次自增

函数模板

模板可以轻松地解决上述问题,减少隐式错误和减少代码冗余。

还是以max举个例子:

template <class T> T max(T x, T y){ return x > y ? x : y; }
函数模板的使用

函数模板的格式:

template <class 形参名1,class 形参名2,......>

返回类型 函数名(参数列表) {

函数体

}

以上面举例的max模板为例:

关键字template后面的尖括号表明,max函数要用到一个叫做T的参数(我们称作模板参数),而这个参数是一种类型。

该模板的含义就是无论参数T为int、char或其他数据类型(包括类类型),函数max的语意都是对x和y求最大值。

这样定义的max代表了一类具有相同程序逻辑的函数,称为函数模板。

注意:使用函数模板时一定要实例化,。

原因:函数模板本身是不被编译器编译的,必须使用实例化给模板T绑定类型后才能使用。

完整使用:

template <class T> T max(T x, T y){ return x > y ? x : y; } //一下是传入模板后编译器扩展结果 //double max(double x, double y) //{ return x > y ? x : y; } int main( ){ double a = 1.0, b2,b1; b1 = max(a, 2.0);//这里是隐式实例化b b2 = max<double>(a, 2.0)//显示实例化 return 0; }

直接使用max()传参识,函数模板接受了一个隐含的参数:double。

编译器自动将函数模板扩展成一个完整的关于double数据比较大小的函数,然后再在函数模板被调用的地方产生合适的函数调用代码。

显示调用就是我们手动转换了传参的类型。

这里有个问题了,既然要实例化才能使用模板,那这里我就需要传入类型不同的参数咋办啊?这里那就需要我们在模板里多写几条class T来分类传入类型了!

template <class T1, class T2> auto max(T1 x, T2 y) { return x > y ? x : y; } //一下是传入模板后编译器扩展结果 //传入res1: //double max(int x, double y) //{ return x > y ? x : y; } //传入res2: //double max(int x, float y) //{ return x > y ? x : y; } int main() { int a = 10; double b = 20.5; float c = 15.8f; auto res1 = max(a, b); cout << "int和double的最大值:" << res1 << endl; auto res2 = max(b, c); cout << "double和float的最大值:" << res2 << endl; return 0; }

当然我还是拿之前的例子举例,这里返回值会被强制全部转换成double返回。但想传入不同类型参数,大抵就是这样使用了。

函数模板传入类类型的使用

模板除了简单的传入类型,我们也可以将自定义类型传入进去,比如这样,我定义有个学生类来比较:

class Student { public: string name; int score; Student(string n, int s) : name(n), score(s) {} }; template <class T> T max(T x, T y) { return x > y ? x : y; } bool operator>(const Student& a, const Student& b) { return a.score > b.score; } int main() { Student s1("张三", 80); Student s2("李四", 90); Student s_max = max(s1, s2); cout << "成绩更高的学生:" << s_max.name << ",成绩:" << s_max.score << endl; return 0; }

当然了,这里的“>”肯定是比较不了我们自定义类型的,所以我们要对此进行一次运算符重载。

模板匹配策略

还有个问题,那就是如果出现了与函数模板相同的函数,那该怎么办?我怎么知道该调用谁?就比如下面这例子:

template <class T> T max(T x, T y){ return x > y ? x : y; } int max(int x, int y){ return x > y ? x : y; } //char max(char x, char y){ // return x > y ? x : y; // } int main( ){ int num=1; char ch=2; int num = 200; // 超过char范围(-128~127) long l = 123456789L; double d = 987654321.0; max(num,num); //调用max(int,int) max(ch,ch); //调用max(T,T),若char max没被注释优先调用char max max(num,ch); //调用max(int,int),char→int // max(num, 'a'); //调用max(char,char ),int→char。 //前提是没用int max(),否则会优先char转化成int。 max(l, d);//调用max(T,T),long→double return 0; }

max模板和max类都满足条件,编译器该怎么判定?

那就来看看匹配规则吧。

在这里优先级从高到低分为四类:

1、完全匹配。

当普通函数和模板都完全匹配时,编译器优先选非模板的普通函数。

如:max(num,num)满足两个函数,那就优先调用普通函数int max()。

2、提升转换(char和short转换为int,及float转换为double)

完全匹配的优先级远高于需要转换,优先调用和实例化完全匹配的函数。

如:max(ch,ch),模板完全匹配可以直接用(完全匹配),而普通函数还要将ch转换为int类型(提升转换),那就优先调用完全匹配的函数模板。

max(num,ch),函数模板只能传入一个类型,这里有两个类型,不满足模板。只能将int隐式转换成char(优先满足提升转换的转换,没有才进行标准转换。)传入int max()。

3、标准转换(int转换为char,及long转换为double)

提升转换与标准转换同时出现,提升转换的优先级大于标准匹配,编译器优先调用满足提升匹配的函数。

如:被注释调的代码 max(num, 'a');,在这里我们将int max()注释掉并且解开char max的注释,函数模板只能传入一个类型,这里有两个类型,不满足模板。只能将int转化成char,完成标准转换。

但注意的是,max(l, d)可以完成long→double的转换从而使用模板函数。

写到这时我发现个这里有一个小问题,前面模板类型使用不是说了max可以隐式转化,这里max(num,ch)中的ch不应该也被转化成int形了吗,那不应该可以传入模板?但实际 max(num,ch)根本传不进去,那为啥 max(l, d)的long→double的转换可以传入模板?

以下为我总结个人理解:

这是因为int与char之间的类型转换有争议,他既可以提升转换也可以标准转换,于是编译器根本不做任何隐式转换,类型推导T不一致,直接失败。

而long与double之间,推导失败后编译器通过模板实参显式指定(隐式的)完成了匹配long→double的隐式转换,并且不存在double→long逆方向,认为逆方向是不合理的,除非我们手动显示转换,不然类型推导T只有long→double着一种情况。

同理,float→double也是一样,他们只有标准转换和提升转换一种种情况。即使我们写了float max和long max,编译器依然不会逆向转换,主动调用模板函数。

PS:这一段理解的我头要秃了,这只是个人理解,还请酌情参考,和指出我的错误>_<

4、用户定义的转换,如类声明中定义的转换。

用户自定义的比较复杂,这里我在重写一个代码:

template <class T> T max(T x, T y){ return x > y ? x : y; } int max(int x, int y){ return x > y ? x : y; } class MyClass { public: int val; MyClass(int v=0) : val(v) {} operator int() const { return val; } bool operator>(const MyClass& o) const { return val > o.val; } }; int main( ){ MyClass obj1(5), obj2(3); // 自定义类型对象 max(obj1, obj2);// 调用模板函数max(MyClass,MyClass) max(obj1, 10);// 调用普通int函数(obj1→int + 10(int),模板推导失败) return 0; }

max(obj1, obj2)可以直接匹配模板(完全匹配),匹配int max需要转换类型。

max(obj1, 10);种,obj1和10的类型不同,匹配模板失败,只能转换obj1类型为int后匹配普通函数。

虽然obj1可以通过operator int() const { return val; } 重写成int型,但可惜模板推导阶段,编译器根本不会主动用operator int() 做转换,只 “机械” 推导实参的原始类型。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 6:05:45

【英飞凌 CY8CKIT-062S2-AI评测】-开发环境搭建与开发

过21IC网&#xff0c;申请到了英飞凌 CY8CKIT-062S2-AI开发板&#xff0c;该开发板是英飞凌的PSOC6系列的人工智能评估套件&#xff0c;它有一套创新工具用来原型制作和收集真实数据&#xff0c;以快速构建机器学习模型。硬件尺寸很小巧35mm*45mm&#xff0c;基于它可以建构边缘…

作者头像 李华
网站建设 2026/3/31 14:27:57

基于SpringBoot2+Vue2的企业合作与活动管理平台

企业合作与活动管理平台 演示视频 https://www.bilibili.com/video/BV1E4qpB9E8b/ 角色 管理员、普通用户、企业用户 技术 后端&#xff1a;Spring Boot 2、MySQL 前端&#xff1a;Vue.js 核心功能 本系统是一个企业合作与活动管理平台&#xff0c;旨在连接企业和普通用…

作者头像 李华
网站建设 2026/3/31 14:04:38

稀土抑烟剂在PVC材料中的防火与抑烟作用

PVC&#xff08;聚氯乙烯&#xff09;因耐用、易加工、成本低&#xff0c;被广泛应用于建筑管材、电线护套、地板和卷材等领域。但在火灾条件下&#xff0c;PVC燃烧容易产生大量烟雾和刺激性气体&#xff0c;不仅影响逃生&#xff0c;也增加了火灾危害。一、什么是稀土抑烟剂&a…

作者头像 李华
网站建设 2026/4/5 23:41:26

别让AI抢了你的饭碗:学会让它替你打工,才是未来的生存法则

朋友们&#xff0c;你有没有想过&#xff0c;未来的世界可能会被简单地分成两种人&#xff1f;一种是让AI替自己干活的人&#xff0c;另一种是活被AI抢走的人。这句话听起来有点残酷&#xff0c;但趋势已经摆在我们眼前。从写报告、做设计&#xff0c;到分析数据、客服应答&…

作者头像 李华
网站建设 2026/4/3 6:31:35

PinMe——极简、免费和无需服务器的开源前端部署工具

PinMe是一个开源的前端部署工具&#xff0c;它通过将静态网站文件上传到去中心化的IPFS网络来实现快速发布&#xff0c;主打极简、免费和无需服务器&#xff0c;目前Github 1.7k stars。 Github地址&#xff1a;https://github.com/glitternetwork/pinme PinMe 的官方网站&am…

作者头像 李华
网站建设 2026/3/30 11:45:38

在 PC 和Android之间同步音乐的 4 种方法

当您的Android设备存储空间越来越少时&#xff0c;您可能希望将整个音乐库同步到电脑进行备份。或者&#xff0c;有时您可能也希望将电脑上的音乐同步到Android &#xff0c;以便随时随地欣赏美妙的音乐。无论您的偏好如何&#xff0c;本文都将为您提供四种在电脑和手机之间同步…

作者头像 李华