如何编写一个通用的函数?
🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏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.…...

【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...

visual studio 2022更改主题为深色
visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...

dify打造数据可视化图表
一、概述 在日常工作和学习中,我们经常需要和数据打交道。无论是分析报告、项目展示,还是简单的数据洞察,一个清晰直观的图表,往往能胜过千言万语。 一款能让数据可视化变得超级简单的 MCP Server,由蚂蚁集团 AntV 团队…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...