如何编写一个通用的函数?
🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏1: 🍔🍟🌯C语言初阶
🐻推荐专栏2: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一
金句分享:
✨你要狠下心来去努力,努力变成一个很厉害的人.✨
前言
本文主要讲解如何使用简单的模板,了解模板的原理以及基本知识.
目录
- 前言
- 一、函数模板
- (1)函数模板的格式
- (2)函数模板的原理(重点)
- (3)模板参数的显示实例化
- (4)模板匹配
- 二、类模板
一、函数模板
模板
的作用:
C++
中模板
的作用是支持泛型编程。==泛型编程=是一种编程范式,它只考虑算法或数据结构的抽象,而不考虑具体的数据类型。通过使用模板,可以编写一种通用的算法或数据结构,而不需要为每种数据类型都编写一遍相关代码。模板可以用于函数、类、结构体等地方,以实现通用的算法和数据结构。使用模板可以提高代码的复用性和可读性,减少代码的重复编写。
示例:实现一个交换函数.
使用模板之前:
void swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}
void swap(double& a, double& b)
{double tmp = a;a = b;b = tmp;
}void swap(char& a, char& b)
{char tmp = a;a = b;b = tmp;
}void test1()
{//交换整形int a = 2, b = 3;cout << "a=" << a << " " << "b=" << b << endl;swap(a, b);cout << "a=" << a << " " << "b=" << b << endl;//交换字符型char c1 = 'd', c2 = 'f';cout << "c1=" << c1 << " " << "c2=" << c2 << endl;swap(c1, c2);cout << "c1=" << c1 << " " << "c2=" << c2 << endl;//交换...
}
上述实现过程中使用函数重载实现.但是函数重载会有一些不合适的问题.
函数重载
只是重载的函数类型不同,代码复用率比较低,对于一个新的类型又要增加新的函数.- 由于功能基本一样,只是类型不同,导致代码的可维护性比较低,一个出错可能所有的重载均出错,均要修改.
这时,函数模板就派上用场了.
(1)函数模板的格式
template<typename T1, typename T2,......,typename Tn>
返回值类型 + 函数名 +(参数列表){}
其中,typename
可以使用class
代替,不能使用struct
代替.
示例:使用模板后的通用交换函数.
template <class T>//模板
void swap(T& a, T& b)//T会根据传参的对象进行推导为相应的类型
{T tmp = a;a = b;b = tmp;
}
void test1()
{//交换整形int a = 2, b = 3;cout << "a=" << a << " " << "b=" << b << endl;swap(a, b);cout << "a=" << a << " " << "b=" << b << endl;//交换字符型char c1 = 'd', c2 = 'f';cout << "c1=" << c1 << " " << "c2=" << c2 << endl;swap(c1, c2);cout << "c1=" << c1 << " " << "c2=" << c2 << endl;//交换...
}
(2)函数模板的原理(重点)
函数模板类似于一个模具,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。所以其实模板
就是将本来应该我们做的重复的事情交给了编译器去做.
这就类似于古代的印刷术,如果每本书都需要手写,那效率是否太低了,还有各种情况可能会出错.但是印刷术的使用,就可以使用模具生成.
函数模板的原理是通过将类型参数化,使函数能够在编译时根据实际参数的类型推断生成具体的函数实例。编译器会根据调用函数时的参数类型,实例化出适合该类型的函数版本。
比如:
当用double
类型使用函数模板时,编译器通过对实参类型的推演,将T
确定为double
类型,然后产生一份专门处理double
类型的代码.当用int
类型使用函数模板时,编译器通过对实参类型的推演,将T
确定为int
类型,然后产生一份专门处理int
类型的代码.如上图所示.
(3)模板参数的显示实例化
上面我们实现的交换函数,模板根据传参时不同的参数,自动推演出函数参数的实际类型.我们称这类通过编译器进行自动推导的实例化模板参数称为模板参数的隐式实例化.
那什么是显示实例化呢?
template <typename T>
T add(const T& a, const T& b)
{return a + b;
}
void test1()
{int a = 2, b = 3;double d1 = 2.5, d2 = 4.1;cout << add(a, b) << endl;cout << add(d1, d2) << endl;//下面这句会报错,因为一个模板参数无法在一个函数中实例化为2个不同类型的参数,一个int,一个double//cout << add(a, d2) << endl;
}
一个函数模板参数在同一个函数中,无法被识别为不同的两个实例类型参数,当编译器推导出a
是int
时,又推出d2
是double
类型,则编译器陷入两难.
就好比:
int
:妈妈说今天不许出去玩!
double
:爸爸说今天可以出去玩!
编译器
:我听谁的.
解决方案:
直接将参数先强转为一样的,当模板函数接收到参数时,就只有一样的结果了.
//解决方法1:传参时将其中不同的参数强转,使参数们相同cout << add(a, (int)d2) << endl;cout << add((double)a, d2) << endl;
模板参数的显示实例化:
让爸妈先商量好听谁的.
//解决方法2:显示指定模板的参数cout << add<int>(a, d2) << endl; //听妈妈的cout << add<double>(a, d2) << endl; //听爸爸的
我们应当是考虑如何在调用时采取不同的调用方式去满足我们的需求,千万不要想着去修改模板函数的返回值,参数使他们固定生成,那模板就不通用了,而且不是什么时候我们都可以去修改模板的.
错误示例:
template <typename T>
T add(const T& a, const int& b)//直接修改参数,进行固定
{return a + b;
}
(4)模板匹配
对于函数名相同的非模板函数和模板函数同时存在时,编译器会优先选择非模板函数.除非模板可以产生更好的匹配函数,才会选择模板.
编译器
:有现成的为啥不用.
void swap(double& a, double& b)
{double tmp = a;a = b;b = tmp;
}
//template <class T>
template <typename T>//函数模板
void swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}
void test1()
{//交换doubledouble d1 = 2.5, d2 = 4.5;//非模板函数和模板函数同时存在时,编译器优先选择非模板函数,有现成的为啥不用?非得自己去再模具刻一个?swap(d1, d2);cout << "d1=" << d1 << " " << "d2=" << d2 << endl;//交换整形int a = 2, b = 3;//没有现成的非模板函数,则编译器调用模板函数去实例化一份swap(a, b);cout << "a=" << a << " " << "b=" << b << endl;
}
交换double
型数据时,会调用void swap(double& a, double& b)
函数,因为有现成的可以调用.
交换int
整形时,则会调用模板函数void swap(T& a, T& b)
,实例化生成int
型的函数.
小知识:
模板函数
不允许自动类型转换,但普通函数可以进行自动类型转换.
因为模板函数的参数是通过参数类型进行推导的.
二、类模板
类模板的格式
template <typename T>
class A
{//成员
}
类模板在后续学习STL
时候会具体介绍,目前了解一下即可,使用方法与函数模板类似,这里就不过多介绍了.
template <typename T>
class A
{
public:A(size_t capacity = 10): _data(new T[capacity]), _size(0), _capacity(capacity){}void push_back() {//...}~A(){delete _data;_size = 0;_capacity = 0;}private:T* _data;size_t _size;size_t _capacity;
};void test3()
{A<int> a1; //实例化为存储int数据的类A<double> a2; //实例化为存储double数据的类
}
本文只是对模板的初步了解,后续会遇到更加复杂的模板,比如多参数的模板等,知识一点点的学,不求速成,坚持一点点的积累,一起加油吧!
今天就讲到这里了,拜拜.
相关文章:
如何编写一个通用的函数?
🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏1: 🍔🍟🌯C语言初阶 🐻推荐专栏2: 🍔🍟🌯C语言进阶 🔑个人信条: 🌵知行合一 金句分享:…...
uni-app封装api请求
前端封装api请求 前端封装 API 请求可以提高代码的可维护性和重用性,同时使得 API 调用更加简洁和易用。 下面是一种常见的前端封装 API 请求的方式: 创建一个 API 封装模块或类:可以使用 JavaScript 或 TypeScript 创建一个独立的模块或类来…...
深度学习从入门到实际项目资料汇总
图片来源于AiLake,如若侵权,请联系博主删除 文章目录 1. 介绍2. 深度学习相关学习资料2.1 [《动手学深度学习》](http://zh.d2l.ai/index.html)2.2 [导航文库](https://docs.apachecn.org/#1be32667e7914f03afb3c39239bd2525)2.3 [AI学习地图,…...
单元测试到底是什么?应该怎么做?
一、什么是单元测试? 单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。至于“单元”的大小或范围,并没有一个明确的标准,“单元”可以是一个函数、方法、类、功能模块或者子系统。 …...
JavaWeb-Listener监听器
目录 监听器Listener 1.功能 2.监听器分类 3.监听器的配置 4.ServletContext监听 5.HttpSession监听 6.ServletRequest监听 监听器Listener 1.功能 用于监听域对象ServletContext、HttpSession和ServletRequest的创建,与销毁事件监听一个对象的事件&#x…...
js数组常用的方法(总结)
目录 1.数组头和尾操作——push、pop、unshift/shift 2、数组转为字符串 —— join() 3、数组截取 —— slice() 4、数组更新 —— splice() 5、反转数组 —— reverse() 6、连接数组 —— concat() 7、ES6连接数组 —— ... ES5数组新增方法 8、索引方法 —— indexO…...
Linux:shell脚本:基础使用(5)《正则表达式-sed工具》
sed是一种流编辑器,它是文本处理中非常中的工具,能够完美的配合正则表达式使用,功能不同凡响。 处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用s…...
关于ubuntu下面安装cuda不对应版本的pyTorch
最近换了台新的linux的ubuntu的服务器,发现其实际安装的cuda版本为11.4,但是pytorch官方给出的针对cuda 11.4并没有具体的pytorch的安装指令,于是采用不指定pytorch版本直接安装让其自动搜索得到即可 直接通过: pip3 install tor…...
【SA8295P 源码分析】26 - QNX Ethernet MAC 驱动 之 emac_rx_thread_handler 数据接收线程 源码分析
【SA8295P 源码分析】26 - QNX Ethernet MAC 驱动 之 emac_rx_thread_handler 数据接收线程 源码分析 一、emac_rx_thread_handler():通过POLL 轮询方式获取数据二、emac_rx_poll_mq():调用 pdata->clean_rx() 来处理消息三、emac_configure_rx_fun_ptr():配置 pdata->…...
70 # 协商缓存的配置:通过修改时间
对比(协商)缓存 比较一下再去决定是用缓存还是重新获取数据,这样会减少网络请求,提高性能。 对比缓存的工作原理 客户端第一次请求服务器的时候,服务器会把数据进行缓存,同时会生成一个缓存标识符&#…...
适合程序员的DB性能测试工具 JMeter
背景 1、想要一款既要能压数到mysql,又要能压数到postGre,还要能压数到oracle的自动化工具 2、能够很容易编写insert sql(因为需要指定表和指定字段类型压数据),然后点击运行按钮后,就能直接运行ÿ…...
java实现人物关系抽取
java实现人物关系抽取 人物关系抽取是实体关系抽取的一种情况。实际上是两个过程:命名实体识别和关系抽取。 Java人物关系抽取是指从文本中提取出与Java相关的人物之间的关系。这个过程可以通过自然语言处理和文本分析的方法来实现。具体的步骤包括: 文本…...
Docker网络与资源控制
一、Docker 网络实现原理 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿…...
图片怎么转换成pdf格式?可以试试这样转换
图片怎么转换成pdf格式?图片转换成PDF格式是一个常见的需求,无论是为了方便存储还是为了分享文件,将图片转换成PDF格式都是一个不错的选择。有许多软件和在线工具可以帮助你完成这个任务,下面就给大家介绍一款转换工具。 【迅捷PD…...
[国产MCU]-W801开发实例-GPIO输入与中断
GPIO输入与中断 文章目录 GPIO输入与中断1、硬件准备2、软件准备3、驱动实现4、驱动测试W801的GPIO支持软件配置中断,中断触发方式包含:上升沿触发、下降沿触发、高电平触发、低电平触发。本文在前面[ 国产MCU]-W801开发实例-按键与GPIO输入的基础上实现GPIO中断配置。 1、硬…...
Layui列表表头去掉复选框改为选择
效果: 代码: // 表头复选框去掉改为选择 $(".layui-table th[data-field"0"] .layui-table-cell").html("<span>选择</span>");...
Flutter实战·第二版-第三章 基础组件笔记
第三章:基础组件 3.1文本及样式 3.1.1 Text Text("Hello world",textAlign: TextAlign.left, );Text("Hello world! Im Jack. "*4,maxLines: 1,overflow: TextOverflow.ellipsis, );Text("Hello world",textScaleFactor: 1.5, );3.1…...
一文彻底理解时间复杂度和空间复杂度(附实例)
目录 1 PNP?2 时间复杂度2.1 常数阶复杂度2.2 对数阶复杂度2.3 线性阶复杂度2.4 平方阶复杂度2.5 指数阶复杂度2.6 总结 3 空间复杂度 1 PNP? P类问题(Polynomial)指在多项式时间内能求解的问题;NP类问题(Non-Deterministic Polynomial)指在…...
Mysql的索引详解
零. 索引类型概述 1. 实际开发中使用的索引种类 主键索引唯一索引普通索引联合索引全文索引空间索引 2. 索引的格式类型 BTree类型Hash类型FullText类型(全文索引)RTree类型(空间索引) MySQL 的索引方法,主要包括 BTREE 和 HASH。 顾名思…...
.netcore windows app启动webserver
创建controller: using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.Json.Serialization; using System.Threading.Tasks;namespace MyWorker.…...
泰迪大数据挖掘建模平台功能特色介绍
大数据挖掘建模平台面相高校、企业级别用户快速进行数据处理的建模工具。 大数据挖掘建模平台介绍 平台底层算法基于R语言、Python、Spark等引擎,使用JAVA语言开发,采用 B/S 结构,用户无需下载客户端,可直接通过浏览器进行…...
【问题】java序列化,什么时候使用
文章目录 是什么为什么如何做流操作 注事事项 是什么 把对象转换为字节序列的过程称为对象的序列化。 把字节序列恢复为对象的过程称为对象的反序列化。 对象的序列化主要有两种用途: 1)把对象的字节序列永久地保存到硬盘上,通常存放在一…...
【最新可用】VMware中ubuntu与主机window之间使用共享文件夹传输大文件
一、VMware设置共享文件夹 (1)虚拟机关机情况下,创建一个共享文件夹 (2)ubuntu中挂载共享文件夹 1、如果之前已经挂载 hgfs,先取消挂载 sudo umount /mnt/hgfs2、重新使用以下命令挂载 sudo /usr/bin/vmh…...
A. Two Semiknights Meet
题目描述 可知走法为中国象棋中的象的走法 解题思路 利用结构体来存储两个 K K K的位置 x , y x,y x,y,因为两个 K K K同时走,所以会出现两种情况 相向而行,两者距离减少 相反而行,两者距离不变 我们完全可以不考虑格子是好…...
〔011〕Stable Diffusion 之 解决绘制多人或面部很小的人物时面部崩坏问题 篇
✨ 目录 🎈 脸部崩坏🎈 下载脸部修复插件🎈 启用脸部修复插件🎈 插件生成效果🎈 插件功能详解🎈 脸部崩坏 相信很多人在画图时候,特别是画 有多个人物 图片或者 人物在图片中很小 的时候,都会很容易出现面部崩坏的问题这是由于神经网络无法完全捕捉人脸的微妙细节…...
在ubuntu+cpolar+rabbitMQ环境下,实现mq服务端远程访问
文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…...
Vue elementui 实现表格selection的默认勾选,翻页记录勾选状态
需求:当弹出一个列表页数据,对其进行筛选选择。 列表更新,填充已选数据 主要使用toggleRowSelection 代码如下: <el-table v-loading"loading" :data"drugList" selection-change"handleSelection…...
CloudCompare——统计滤波
目录 1.统计滤波2.软件实现3.完整操作4.算法源码5.相关代码 本文由CSDN点云侠原创,CloudCompare——统计滤波,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 1.统计滤波 算法原理见:PCL 统计滤波器…...
nodejs+vue古诗词在线测试管理系统
一开始,本文就对系统内谈到的基本知识,从整体上进行了描述,并在此基础上进行了系统分析。为了能够使本系统较好、较为完善的被设计实现出来,就必须先进行分析调查。基于之前相关的基础,在功能上,对新系统进…...
174-地下城游戏
题目 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里,他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数。如果他的健康点数在某一时刻…...
怎么把dw做的网站分享给别/世界足球排名最新
在 SharePoint Server 2013 中备份 User Profile Service 应用程序 摘要:了解如何备份 SharePoint 2013 中的 User Profile Service 服务应用程序。 可使用 SharePoint 管理中心网站、Windows PowerShell 或 SQL Server 工具备份 User Profile Service 应用程序。您…...
wordpress评论时选填/影视网站怎么优化关键词排名
微信的JS-SDK通过config接口注入权限验证配置,官网上的文档说的很清楚:wx.config({debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来,若要查看传入的参数,可以在pc端打开,参数信息会通过log打出…...
网站修改影响做百度竞价吗/网站seo设置是什么
写在前面:楼主毕业后所在的公司属于互联网电商成长型公司,不用融资,系集团内部自主创业,由于待遇还有福利什么的在本市还行,最主要是有一帮年轻人在工作,自己发展的机会也是很多的,然后就入坑了,…...
网站优化公司哪家便宜/个人博客网站设计毕业论文
转自:http://blog.csdn.net/luo3532869/article/details/7605414 printk的日志级别有八个分别为KERN_EMERG、 KERN_ALERT、 KERN_CRIT、 KERN_ERR 、 KERN_WARNNING、 KERN_NOTICE、 KERN_INFO 、KERN_DEBUG printk默认的级别是DEFAULT_MESSAGE_LOGLEVEL,…...
《电子商务网站开发实训》总结/windows优化大师和鲁大师
1. 官方文档 代码编译后的生产目录 2. 实际开发问题 不同端程序的打包,都会生成到dist文件夹下边,这就导致如果同时多端调试或者打包,会很麻烦!不同程序的打包命令! /package.json "build:weapp": "taro build --type weapp", "build:swan&qu…...
个人业务网站源码php/西安今天出大事
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼(二)破格条件基本条件中的第4、5款为必须具备的条件,不能破格。1.一般破格达到以下条件中的一条可进行一般破格:(1)在本科学习期间获得相关专业的具有学术意义的省级一等奖、国家二等奖以上各类学…...