C++【模板初阶】
✨个人主页: Yohifo
🎉所属专栏: C++修行之路
🎊每篇一句: 图片来源
No one saves us but ourselves, no one can and no one may. We ourselves must walk the path.
- 除了我们自己,没有人能拯救我们,没有人可以,也没有人可以。我们自己必须走这条路。
文章目录
- 📘前言
- 📘正文
- 📖范型编程
- 📖函数模板
- 🖋️使用方法
- 🖋️实现原理
- 💡隐式实例化
- 💡显式实例化
- 🖋️匹配规则
- 🖋️注意事项
- 📖类模板
- 🖋️使用方法
- 🖋️注意事项
- 📘总结
📘前言
早在北宋年间,中国的毕昇就已经发明了泥活字,标志着四大发明之一的活字印刷术正式诞生,从此文化传播取得了革命性突破,各种文学作品得以走进千家万户。倘若这项技术还没有被发明,那么恐怕我们现在的书本都还得靠逐字手抄传播,效率是非常低的
我们的程序也是如此,很多需要频繁使用的函数每次都得手动写,这可难不倒程序员,于是在上世纪80年代末,范型编程思想正式诞生,它就像是印刷文字的模具,将程序主体刻在其中,需要使用时让编译器根据参数类型生成即可,这就是我们今天的主角模板

📘正文
模板的产生源自于范型编程的思想,简单来说,就是将算法抽象化编写
📖范型编程
那么什么才是一个抽象化的算法呢?
比如我们常用的两数相加函数,按照以前的写法,处理整型数据时,编写整型的方法;处理浮点型时,又得编写一个浮点型的加法,好在C++支持函数重载,使得我们可以存在同名函数,假若是C语言实现时,我们甚至要写两个不同名的相加函数
//处理整型的加法函数
int Add(const int& a, const int& b)
{return a + b;
}//处理浮点型的加法函数
double Add(const double& a, const double& b)
{return a + b;
}
两数相加,直接返回两数之和就行了,我们实现方法时,没必要关注具体数据类型
将具体问题抽象化,直接假设数据类型为 T,利用模板实现如下:
//利用模板实现函数
template <class T> //模板关键字
T Add(const T& a, const T& b)
{return a + b;
}
此时我们只编写了一个加法函数模板,而所有类型的参数都可以调用加法函数

具体问题抽象化就是范型编程的核心思想
📖函数模板
首先来看模板在函数实现上的运用
注意:
- 模板关键字为
template - 形式为
template <class T>或者template <typename T> - 其中的
T是模板中的参数名,我们可以自定义 - 模板中可以存在多个参数,通过
,号分隔
🖋️使用方法
模板函数即在函数实现之前,写好模板,再根据模板中定义的变量名实现函数
//实现所有类型数组的打印
//这种模板写法也是没有问题的
template <typename Type>
void CoutArray(const Type& arr)
{//范围 for ,C++11 中的语法糖for (auto e : arr){cout << e << " ";}cout << endl;
}

我们还可以实现多参数模板
//多参数模板
//这里实现的是val2强制类型转换为val1,并取得和
template <class T1, class T2>
T1 getTrunVal(const T1& val1, const T2& val2)
{const T1 tmp = (const T1)val2;return val1 + tmp;
}

总之,在函数模板的存在下,我们不再需要再编写不同类型参数的相似函数了
🖋️实现原理
这个模板看着挺厉害,那么它的实现原理是什么呢?
其实很简单,只需要两样东西:编译器 和 函数重载
当我们编写好函数模板后,编译器会记住这个模板的内容,当我们使用模板时,编译器又会根据参数类型,创建相应的、具体的函数供参数使用,而这就是函数重载的道理
形象化理解:
- 假设我们的整个
程序就是一个大城市 - 在这个城市中,我们就是
造物主,编译器则是负责协助我们处理事情的 - 假设在某一天,
参数A提出它需要一栋房子(方法),造物主很不屑的给造好了房子 - 一天后,
参数B也说它也需要一栋房子(方法),造物主很快就满足了它的需求 - 之后的每一天中,都会有
参数说自己需要房子(方法),于是造物主坐不住了,他觉得这些参数很麻烦,明明大家都是同一个需求,还得自己不断重复实现 - 于是他想了一个办法:将建造房子的
图纸(模板)交给编译器,编译器是完全服从于造物主的,造物主说:“小编啊,以后再有人找我建房子(方法),你就按照这个图纸(模板)去建造,建好后将房子所有者变成它就行了”,这样一来,造物主的工作量就减小了很多,重复相似的工作直接提供蓝图(模板),然后让编译器根据参数类型落实即可 - 于是,
函数模板就这样诞生了

可以看出,不断建房子这件麻烦事仍然存在,毕竟不可能让所有参数都入住一栋房子,函数模板 的本质就是将实现不同参数的相似方法这件事交给编译器去完成,我们只需要提供蓝图(模板)即可
比如文章开头中的 Add 函数,我们提供了模板,当实际调用函数时,编译器会自动识别参数类型,然后生成对应的函数,供参数调用,也就是说,编译器根据不同参数,老老实实生成了 int、double、char 三个版本的 Add 函数,如果有需要,它还能继续生成
实际参数调用时,调用的是模板生成的对应函数,而非模板本身!
编译器在识别参数类型生成函数时,有两种途径:
- 自动识别 (
隐式) - 我们手动指定(
显式)
💡隐式实例化
隐式实例化就是编译器自动识别参数后生成函数的过程
隐式实例化很方便,但可能存在问题
//Add 模板
template <class T>
T Add(const T& a, const T& b)
{return a + b;
}int main()
{Add(2, 1.5); //此时编译失败!return 0;
}

原因:
- 此时我们的模板是单参数模板
- 因为是编译器
隐式实例化,当编译器识别到2时,将生成int型方法 - 此时
Add函数内的两个形参类型都为int,实际函数名修饰为_3Addii - 而我们的参数2为
double,是一个浮点型数据,实际函数调用时,找的是这个函数_3Addid - 此时出现明显的链接错误,编译器索性直接在编译前就已经报错阻拦
解决方法:
- 将参数2强制类型转换为
int,或者将参数1强制类型转换为double都能解决问题 - 多参数模板也能解决问题,此时如果识别到两个不同的参数,编译器就会根据实际情况生成函数
- 还有一种解决方法就是
显式实例化

注意:
强制类型转换后生成临时变量进行传参- 临时变量具有常性,所以Add函数中的引用形参需要被 const 修饰
- 或者不用引用,这样也不需要
const,但是此时效率会变低
💡显式实例化
显式实例化就是给编译器打招呼,让它在建房子时按照我们的意愿来
Add<int> (2, 3.14); //此时编译器会调用 _3Addii 函数,至于传参时的类型转换,由编译器完成
Add<char> (2, 5); //调用 _3Addcc 函数
这种行为是完全合法的,< > 符号也正式和我们见面了,在后面的 STL 学习中,< > 会经常使用到,比如生成一个类型为 int 的顺序表,直接 vector<int>,生成 char 类型的顺序表 vector<char>,一键生成,非常方便,当然还有很多容器都会用到显式实例化
🖋️匹配规则
具体函数调用时,隐式生成的模板函数并不会最先被调用
假设我们已经在程序中写好了参数需要的函数,而同时模板也能生成参数需要的函数,此时编译,编译器会先寻找是否存在目标函数,如果有,编译器便不再根据函数模板生成函数,避免造成代码冗余
我们可以通过调试来观察到这一现象

🖋️注意事项
注意:
- 函数调用时,并非直接调用
函数模板,而是调用编译器根据参数类型和模板生成的函数 - 使用模板是在麻烦
编译器帮我们办事,实际事也是办成功的 - 当
隐式实例化后的函数已存在时,不会去生成模板函数,而是直接使用已存在的函数 显式实例化后,编译器则会优先选择显式生成的普通函数隐式生成的模板函数不存在类型隐式类型转换,显式后生成的是普通函数,可以隐式类型转换
模板中的参数类型不能为 strcut
template<struct T> //这种定义是非法的
C++库中存在一个 swap 函数,它能实现所有数据类型的交换,其实它就是通过函数模板实现的

📖类模板
模板除了可以用在函数上面外,还可以用在类上,此时称为 类模板
STL 库中的容器,都是 类模板 的形式,我们使用时,需要什么类型的 类,直接显式实例化为对应 模板类 即可
//简单演示下 STL 中的容器,这些都是类模板的实际运用
vector<int> v1; //实例化为整型顺序表类
list<double> l1; //实例化为浮点型链表类
🖋️使用方法
类模板和函数模板有所不同,类模板只能显式实例化
//简单写一个栈模板
template<class T>
class Stack
{
public://构造函数Stack(int capacity = 4);//析构函数~Stack();//……private:T* _pData;int _top;int _capacity;
};//注意类模板中方法的实现方式!
//定义构造函数
template<class T>
Stack<T>::Stack(int capacity)
{_pData = new T[capacity]; //内存管理,一次申请4块空间_capacity = capacity;_top = 0;
}//定义析构函数
template<class T>
Stack<T>::~Stack()
{delete[] _pData; //注意:匹配使用_capacity = _top = 0;
}//……
这就算 STL 库中 stack 的简陋版本,还有很多方法没实现,但大体逻辑都是如此

🖋️注意事项
类模板使用时需要注意一些问题:
模板类中的函数在定义时,如果没有在类域中,就需要通过类模板+类域访问的方式定义类模板不支持声明与定义分开在两个文件中实现,因为会出现链接错误
📘总结
以上就是关于 C++ 模板初阶 的全部内容了,模板是一个很实用的工具,它可以提高我们的编码效率,省去很多不必要的麻烦,善用模板,快乐编程!
如果你觉得本文写的还不错的话,可以留下一个小小的赞👍,你的支持是我分享的最大动力!
如果本文有不足或错误的地方,随时欢迎指出,我会在第一时间改正

相关文章推荐 C/C++【内存管理】
===============
类和对象实操
类和对象实操之【日期类】
===============
类和对象系列
类和对象(下)
类和对象(中)
类和对象(上)
![]()
相关文章:
C++【模板初阶】
✨个人主页: Yohifo 🎉所属专栏: C修行之路 🎊每篇一句: 图片来源 No one saves us but ourselves, no one can and no one may. We ourselves must walk the path. 除了我们自己,没有人能拯救我们…...
华为OD机试 - 磁盘容量(Python)| 真题+思路+考点+代码+岗位
磁盘容量 题目 磁盘的容量单位常用的有M、G、T 他们之间的换算关系为1T =1024G,1G=1024M 现在给定n块磁盘的容量,请对他们按从小到大的顺序进行稳定排序 例如给定5块盘的容量 5 1T 20M 3G 10G6T 3M12G9M 排序后的结果为 20M 3G 3M12G9M 1T 10G6T 注意单位可以重复出现 上述…...
更专业、安全、可控!政企都选择WorkPlus私有化部署
现如今政企机构在信息化建设的过程中,内部的沟通协作都离不开即时通讯软件。但大多数企业使用的即时通讯软件都是Saas部署的,虽然使用Saas部署产品成本低,又方便快捷,但还是建议企业有条件最好使用私有化部署的即时通讯软件&#…...
[SDX12] X12 USB to LTE IPA概率不生效问题分析及优化策略
问题描述 在测试USB to LTE的流量过程中,发现IPA概率失效,正常可以跑到320Mbps,但是跑流1分钟左右会出现IPA失效及跑流掉坑的情况。 问题log dmesg log 3,1862,149793394,-;ipa ipa3_ioctl:3564 using obselete command: IPA_IOC_RM_ADD_DEPENDENCY 3,1863,149793549,-;ipa …...
mysql8.0(单表查询与多表拆线)
目录 单表查询 1、显示所有职工的基本信息。 2、查询所有职工所属部门的部门号,不显示重复的部门号。 3、求出所有职工的人数。 4、列出最高工资和最低工资。 5、列出职工的平均工资和总工资。 6、创建一个只有职工号、姓名和工作时间的新表&…...
用于汽车传感器的混合点云语义压缩:性能评估
Hybrid Point Cloud Semantic Compression for Automotive Sensors: A Performance Evaluation https://arxiv.org/pdf/2103.03819.pdf 在自动驾驶中,车辆与车辆之间的信息共享起着重要作用。在所有传感器中,激光雷达产生的3D点云的数据量通常较高。因…...
最流行十大在线客服系统排行榜-市场常见客服系统软件排行-2023最新
2023年榜单规则依据 在线客服系统十大品牌榜数据由CNPP品牌榜中榜大数据「研究院」和CN10排排榜技术「研究院」通过资料收集整理,并基于大数据统计及人为根据市场和参数条件变化的分析研究专业测评而得出,是大数据、云计算、数据统计真实客观呈现的结果&…...
算法笔记(六)—— 二叉树相关概念及经典算法题
二叉树的相关概念(判断方式) 1. 搜索二叉树:对每棵子树,左树比头小,右树比头大。 中序遍历,判断是否升序 2. 完全二叉树:最后一层满或从左到右遍满。 宽度遍历,如果有节点有右孩子…...
redux全网最详细教程
一.路由懒加载 关键点: lazy懒加载 Suspense组件(添加加载提示) utils文件夹 –LazyLoad.js //lazy懒加载 Suspense 组件(添加加载提示) import {lazy,Suspense} from react export default function LazyLoad(url)…...
华为OD机试 - 匿名信(Python)| 真题+思路+考点+代码+岗位
匿名信 题目 电视剧《分界线》里面有一个片段,男主为了向警察透露案件细节,且不暴露自己,于是将报刊上的字减下来,剪拼成匿名信。 现在又一名举报人,希望借鉴这种手段,使用英文报刊完成举报操作。 但为了增加文章的混淆度,只需满足每个单词中字母数量一致即可,不关注…...
【Python】编写代码实现指定下标值顺序进行正序和倒序排序算法编程
🎉🎉 在本次python文章中,主要通过定义一个排序方法,实现一组数列能够按照另一组数列指定的位置进行重新排序输出,默认正序排序,可通过True表示逆序输出 目录1、知识点2、数列和元组1)错误遍历方…...
Sitara™处理器的产品开发路线图
Sitara™处理器的产品开发路线图概述Evaluation Phase(评估阶段)Board Development Phase(硬件发展阶段,硬件设计人员应重点关注这个阶段)Software Development Phase(软件发展阶段)Product Phase/SW Lifecycle概述 一般情况下,会存在四个主要的发展阶段…...
岗位来啦-华为研发OD招聘
研发OD招聘 ★★关于我们★★ 万物互联时代已到来,无线通信技术正在重塑世界。作为行业领导者,华为无线致力于通过移动创新消除数字鸿沟,构建万物互联的智能世界。基于5G的技术,家庭无线宽带接入、车联网、云AR/VR、eMBB高清视频…...
【LeetCode】剑指 Offer 06. 从尾到头打印链表 p58 -- Java Version
题目链接: https://leetcode.cn/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof/ 1. 题目介绍(06. 从尾到头打印链表) 输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。 【测试用例…...
童年回忆--扫雷(包括标记功能和递归展开)--万字讲解让你学会扫雷制作
魔王的介绍:😶🌫️一名双非本科大一小白。魔王的目标:🤯努力赶上周围卷王的脚步。魔王的主页:🔥🔥🔥大魔王.🔥🔥🔥 ❤️…...
【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理
【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理 【重器】GPS北斗卫星时钟基准与卫星授时服务技术原理 1.前言 由计算机网络系统组成的分布式系统,若想协调一致进行:IT行业的“整点开拍”、“秒杀”、“Leader选举”,通信行业的“同步组网…...
软件测试未来发展趋势怎么样
未来,互联网技术是很多企业能够活下去的关键点。互联网技术成为新的基建,互联网“基建”化就决定了软件测试行业的缺口会一直扩大。 并且,软件测试岗位,已不仅局限于互联网企业,现已逐步深入到实体产业,金…...
aws Distro for OpenTelemetry 可观测性workshop记录
参考资料 https://aws-otel.github.io/docs/introductionhttps://aws-otel.github.io/docs/introduction aws distro for opentelemetry 官方提供了不同语言不同使用场景下完善的使用实例和相关配置。 AWS Distro for OpenTelemetrics 由以下部分组成,用于向后端…...
Leetcode力扣秋招刷题路-0068
从0开始的秋招刷题路,记录下所刷每道题的题解,帮助自己回顾总结 68. 文本左右对齐 给定一个单词数组 words 和一个长度 maxWidth ,重新排版单词,使其成为每行恰好有 maxWidth 个字符,且左右两端对齐的文本。 你应该…...
Nginx介绍及安装(windows版,Linux版)
目录 一、Nginx介绍 1、Nginx优势 2、Nginx作用 3、部署静态资源 4、代理 5、负载均衡 二、Nginx安装步骤(windows版) 三、Nginx安装步骤(Linux版) 1、官网下载安装包,下载完之后上传到Linux系统上 2、在Lin…...
IDEA运行Tomcat出现乱码问题解决汇总
最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...
基于距离变化能量开销动态调整的WSN低功耗拓扑控制开销算法matlab仿真
目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.算法仿真参数 5.算法理论概述 6.参考文献 7.完整程序 1.程序功能描述 通过动态调整节点通信的能量开销,平衡网络负载,延长WSN生命周期。具体通过建立基于距离的能量消耗模型&am…...
遍历 Map 类型集合的方法汇总
1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...
Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)
引言:为什么 Eureka 依然是存量系统的核心? 尽管 Nacos 等新注册中心崛起,但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制,是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...
【JVM面试篇】高频八股汇总——类加载和类加载器
目录 1. 讲一下类加载过程? 2. Java创建对象的过程? 3. 对象的生命周期? 4. 类加载器有哪些? 5. 双亲委派模型的作用(好处)? 6. 讲一下类的加载和双亲委派原则? 7. 双亲委派模…...
yaml读取写入常见错误 (‘cannot represent an object‘, 117)
错误一:yaml.representer.RepresenterError: (‘cannot represent an object’, 117) 出现这个问题一直没找到原因,后面把yaml.safe_dump直接替换成yaml.dump,确实能保存,但出现乱码: 放弃yaml.dump,又切…...
链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
python打卡day49@浙大疏锦行
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 一、通道注意力模块复习 & CBAM实现 import torch import torch.nn as nnclass CBAM(nn.Module):def __init__…...
【技巧】dify前端源代码修改第一弹-增加tab页
回到目录 【技巧】dify前端源代码修改第一弹-增加tab页 尝试修改dify的前端源代码,在知识库增加一个tab页"HELLO WORLD",完成后的效果如下 [gif01] 1. 前端代码进入调试模式 参考 【部署】win10的wsl环境下启动dify的web前端服务 启动调试…...

