【C++】初步认识模板
🏖️作者:@malloc不出对象
⛺专栏:C++的学习之路
👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈
目录
- 前言
- 一、泛型编程
- 二、函数模板
- 2.1 函数模板的原理
- 2.2 函数模板的实例化
- 2.3 模板参数的匹配原则
- 三、类模板
- 3.1 类模板的实例化
- 3.2 类模板与模板类
前言
本篇文章我们讲解的是模板,它极大的节省了我们成本去构造多份差不多的代码,它是复用性很强的一种手段,下面就让我们初步认识一下模板吧。
一、泛型编程
如何实现一个通用的交换函数呢?我们可能会写出多个交换函数的版本:
void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}
// ......
使用函数重载虽然可以实现多版本的交换函数,但是有一下几个不好的地方:
1.重载的函数仅仅是类型不同,代码复用率比较低,只要有新类型出现时,就需要用户自己增加对应的函数
2.代码的可维护性比较低,一个出错可能所有的重载均出错
那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?


如果在C++中,也能够存在这样一个模具,通过给这个模具中填充不同材料(类型),来获得不同材料的铸件(即生成具体类型的代码),那将会节省许多时间。基于这样的原因,模板就被C++之父设计出来了。
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。

二、函数模板
函数模板概念:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。
函数模板格式
template<typename T1, typename T2,......,typename Tn>,同样也可以使用template<class T1, class T2, ......, class Tn>,关于这两种方式的区别我们后续再来谈。
返回值类型 函数名(参数列表){}
下面我们先来简单的看看它的用法:
#include <iostream>
using namespace std;//template<class T>
template<typename T>
void Swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}int main()
{int a = 1, b = 2;Swap(a, b);cout << a << " " << b << endl;double c = 1.2, d = 3.4;Swap(c, d);cout << c << " " << d << endl;return 0;
}

从上述结果中我们发现利用函数模板的确实现了不同版本的交换函数,那么函数模板它到底是如何实现不同版本的交换函数的呢?我们调用函数时都是调用的函数模板吗?
2.1 函数模板的原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具,所以其实模板就是将本来应该我们做的重复的事情交给了编译器去完成。

在编译器编译阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对应类型的函数以供调用。比如:当用double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后产生一份专门处理double类型的代码,对于其他数据类型也是如此。
我们通过反汇编来查看一下这其中的逻辑:

我们发现编译器根据传入的实参类型自动推演生成对应类型的函数,实际我们调用的也就是编译器自动生成的函数。
2.2 函数模板的实例化
函数模板实例化:用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式实例化和显式实例化。
- 隐式实例化:让编译器根据实参推演模板参数的实际类型
#include <iostream>
using namespace std;template<class T>
T Add(const T& left, const T& right)
{return left + right;
}int main()
{int a1 = 10, a2 = 20;double d1 = 10.2, d2 = 20.3;// 实参传递给形参,自动推演模板类型cout << Add(a1, a2) << endl;cout << Add(d1, d2) << endl;return 0;
}

如果我们想传递两个类型不同的实参进行相加,是否能够达到目的呢?

从报错信息我们知道,此时我们的模板参数类型都是T,那么在传递实参时一个为int类型一个为double类型,此时模板参数类型就确定不了,编译器也不敢擅自做类型转换操作,那么我们该如何操作呢?
第一种方法就是进行强制类型转换,使模板参数类型保持一致,然后实例化出对应的函数模板:

注:上述的模板参数必须使用const修饰,因为强制类型转换会产生临时变量,临时变量具有常属性,实参具有常属性那么形参也要保持一致!!!
- 显式实例化:在函数名后的<>中指定模板参数的实际类型

指明模板参数的实际类型之后,如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。
上述两个实参类型不同而模板参数类型是一致的,所以我们需要保持实参类型一致才能实例化出对应的函数,那么我觉得这个地方其实是有些别扭且不方便的,我们就是想让类型不一致的进行相加呢?
实际上我们的模板参数类型并不一定只有一种,这里我们可以使用两种模板参数类型来完成这个任务:

注:上述模板参数返回类型可以是T1也可以是T2,可以按照自己的需求来设计。
2.3 模板参数的匹配原则
- 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数

一个非模板函数可以和一个同名的函数模板同时存在,这其实也说明了函数模板实例化出来的函数与非模板函数是独立的两份不同的函数,它们的函数名经过修饰后也必定是不一致的。
- 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。
以下图为例,当非模板函数和一个同名的函数模板同时存在时,编译器会优先去考虑效率高的方式(最为合适的方式)。

- 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
三、类模板
类模板的定义格式
template<class T1, class T2, ..., class Tn> class 类模板名 { // 类内成员定义 };
我们先来看一个简单的例子:
typedef double STDataType;class Stack
{
public:Stack(size_t capacity = 0){_a = new T[5];_top = 0;_capacity = capacity;}~Stack(){delete[] _a;_capacity = _top = 0;}private:STDataType* _a;size_t _top;size_t _capacity;
};
利用typedef我们就能实现多种数据类型的栈结构,增强了代码的维护性,但是如果我想要同时实现多份不同数据类型的栈结构呢?此时我们使用typedef还能做到吗?答案是不行的,typedef只适用于实现一份数据类型的栈结构,,那么我们想同时实现多份不同数据类型的栈结构就只能使用我们的类模板了。
3.1 类模板的实例化
类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后跟<>,然后将实例化的类型放在<>中即可,类模板名字不是真正的类,而实例化的结果才是真正的类。

函数模板实参传递给形参时可以推演模板参数类型,而类模板是不确定的,在实例化对象调用构造函数初始化过程中,模板参数是不确定的。如上图在对象实例化时,调用构造函数此时我们的模板参数类型T无从得知。
注:类模板必须显式实例化!!!
3.2 类模板与模板类
类模板是一个类家族,模板类是通过类模板实例化的具体类。类模板的重点是模板表示的是一个模板,专门用于产生类的模子;模板类的重点是类,表示的是由一个模板生成而来的类,类模板中的虚拟类型参数指定成一个具体的数据类型参数就是模板类。更通俗一点来说,类模板可以看作是做蛋糕的模具,模板类可以看作是通过蛋糕模具做出来的蛋糕。

下面我们来看一个例子,来讲讲类模板的性质:
// 注意:Vector不是具体的类,是编译器根据被实例化的类型生成具体类的模具
template<class T>
class Vector
{
public :Vector(size_t capacity = 10): _pData(new T[capacity]), _size(0), _capacity(capacity){}// 使用析构函数演示:在类中声明,在类外定义。~Vector();void PushBack(const T& data);void PopBack();// ...size_t Size() {return _size;}T& operator[](size_t pos){assert(pos < _size);return _pData[pos];}
private:T* _pData;size_t _size;size_t _capacity;
};// 注意:类模板中函数放在类外进行定义时,需要加模板参数列表
template <class T>
Vector<T>::~Vector()
{if(_pData)delete[] _pData;_size = _capacity = 0;
}int main()
{Vector<int> v1; // Vector类名,Vector<int>才是类型Vector<double> v2;return 0;
}
上述例子中Vector就是类模板,Vector<int>、Vector<double>都是模板类。
类模板的性质:
1.如果一个类被声明为类模板,那么其中的所有成员函数都是模板函数。
2.类模板中函数放在类外进行定义时,需要加模板参数列表。
3.模板的定义与声明不能分离!!!(这点我们以后再来探讨)。
本篇文章的内容就到这里了,如果文章有任何疑问或者错处欢迎大家评论区相互交流orz~🙈🙈
相关文章:
【C++】初步认识模板
🏖️作者:malloc不出对象 ⛺专栏:C的学习之路 👦个人简介:一名双非本科院校大二在读的科班编程菜鸟,努力编程只为赶上各位大佬的步伐🙈🙈 目录 前言一、泛型编程二、函数模板2.1 函…...
Ansible 临时命令搭建安装仓库
创建一个名为/ansible/yum.sh 的 shell 脚本,该脚本将使用 Ansible 临时命令在各个受管节点上安装 yum 存储库. 存储库1: 存储库的名称为 EX294_BASE 描述为 EX294 base software 基础 URL 为 http://content/rhel8.0/x86_64/dvd/BaseOS GPG 签名检查为…...
phpstorm动态调试
首先在phpstudy搭建好网站,在管理拓展开启xdebug拓展 查看php.ini配置已经更改 需要增添修改一下设置 [Xdebug] zend_extensionD:/phpstudy_pro/Extensions/php/php5.6.9nts/ext/php_xdebug.dll xdebug.collect_params1 xdebug.collect_return1 xdebug.auto_trace…...
二叉树的层序遍历及完全二叉树的判断
文章目录 1.二叉树层序遍历 2.完全二叉树的判断 文章内容 1.二叉树层序遍历 二叉树的层序遍历需要一个队列来帮助实现。 我们在队列中存储的是节点的地址,所以我们要对队列结构体的数据域重定义, 以上代码 从逻辑上来讲就是1入队,1出队&am…...
java八股文面试[JVM]——JVM内存结构
参考: JVM学习笔记(一)_卷心菜不卷Iris的博客-CSDN博客 JVM是运行在操作系统之上的,它与硬件没有直接的交互 JVM内存结构: 方法区:存储已被虚拟机加载的类元数据信息(元空间) 堆:存放对象实…...
Kafka基本使用
查看Kafka的进程是否在运行 #命令行终端中运行如下命令 ps -ef | grep kafkafind / -iname kafka-server-start.shcd /usr/local/kafka/bin/#启动kafka ./kafka-server-start.sh -daemon /usr/local/kafka/config/server.propertiesKafka默认使用9092端口提供服务…...
【目标检测】理论篇(2)YOLOv3网络构架及其代码实现
网络构架图: 代码实现: import math from collections import OrderedDictimport torch.nn as nn#---------------------------------------------------------------------# # 残差结构 # 利用一个1x1卷积下降通道数,然后利用一个3x3卷…...
k8s之工作负载、Deployment、DaemonSet、StatefulSet、Job、CronJob及GC
文章目录 1、工作负载1.1、定义1.2、分类 2、Deployment2.1、定义2.2、Deployment创建2.3、Deployment 更新机制2.3.1、比例缩放(Proportional Scaling)2.3.2、HPA(动态扩缩容)2.3.2.1、需要先安装metrics-server2.3.2.2、配置hpa…...
IDEA项目实践——Element UI概述
系列文章目录 IDEA项目实践——JavaWeb简介以及Servlet编程实战 IDEA项目实践——Spring当中的切面AOP IDEA项目实践——Spring框架简介,以及IOC注解 IDEA项目实践——动态SQL、关系映射、注解开发 IDEWA项目实践——mybatis的一些基本原理以及案例 文章目录 …...
Docker 容器学习笔记
Docker 容器学习笔记 容器的由来 早先,虚拟机通过操作系统实现相互隔离,保证应用程序在运行时相互独立,避免相互干扰。但是操作系统又笨又重,耗费资源严重: 容器技术只隔离应用程序的运行时环境但容器之间共享同一个…...
Day03-vue基础
Day03-vue基础 一 列表渲染 v-for这个指令可以实现列表渲染 1 数组 <ul><!-- v-for遍历的时候,key必须赋唯一值第一个参数是数组元素,第二个参数是元素下标--><li v-for="(item,index) in [1,3,5,7]" :key="item">{{item}}--{{index}…...
RAC sid=‘*‘ 最好加上 v$system_parameter
实验结论:在RAC环境中,最好修改参数sid* 安全可靠,因为暂时未明确知道哪些参数是默认全局修改,什么参数是默认单节点修改的,* 靠谱,不容易出问题 在RAC环境中,修改全局参数scopespfile生效时&am…...
【位运算进阶之----左移(<<)】
今天我们来谈谈左移这件事。 ❤️简单来说,对一个数左移就是在其的二进制表达末尾添0。左移一位添一个0,结果就是乘以2;左移两位添两个0,结果就乘以2 ^ 2;左移n位添n个0,结果就是乘以2 ^ n,小心…...
石油石化行业网络监控运维方案,全局态势感知,实时预警
石油石化行业是一个高科技密集型行业,投资巨大、人员众多,各产业价值链的关联度较高,大型石油石化企业实现了上中下游产业的一体化协同发展。随着工业4.0时代的来临,信息化和工业化融合,物联网、云计算等新技术的普及推…...
MyBatis 的关联关系配置 一对多,一对一,多对多 关系的映射处理
目录 一.关联关系配置的好处 二. 导入数据库表: 三. 一对多关系:-- 一个订单对应多个订单项 四.一对一关系:---一个订单项对应一个订单 五.多对多关系(两个一对多) 一.关联关系配置的好处 MyBatis是一…...
Diffusion Models for Image Restoration and Enhancement – A Comprehensive Survey
图像恢复与增强的扩散模型综述 论文链接:https://arxiv.org/abs/2308.09388 项目地址:https://github.com/lixinustc/Awesome-diffusion-model-for-image-processing/ Abstract 图像恢复(IR)一直是低水平视觉领域不可或缺的一项具有挑战性的任务&…...
Springboot开发所遇问题(持续更新)
SpringBoot特征: 1. SpringBoot Starter:他将常用的依赖分组进行了整合,将其合并到一个依赖中,这样就可以一次性添加到项目的Maven或Gradle构建中。 2,使编码变得简单,SpringBoot采用 JavaConfig的方式对Spring进行配置…...
智能电视与win10电脑后续无法实现DLNA屏幕共享
问题背景: 我用的是TCL电视,但是并不是最新,打开的方式是U盘->电脑,各位看自己情况,很多问题都大概率是智能电视问题。 情景假设: 假设你已经完成原先智能电视该有的步骤,通过DLNA…...
如何可以管理监督员工工作微信?
自从微信管理系统研发上线之后,为了各企业带来了福音。 很多用户企业都是这样评论微信管理系统的:员工的所有微信聊天记录后台都可以清楚明了的看到,聊天记录都是永久保存的,不担心员工在手机上把聊天记录删除,杜绝员…...
【Django】如何转化已有的数据表到Django模型--20230823
初步生成model.py $ python manage.py inspectdb $ python manage.py inspectdb > models.py python manage.py inspectdb # This is an auto-generated Django model module. # Youll have to do the following manually to clean this up: # * Rearrange models order…...
AI首推路径控制引擎
AI首推路径控制引擎版本:v2.0.0 发布日期:2026年3月26日 发布状态:正式全量发布---一、背景与概述在AI生成式应用中,模型输出的随机性与不可控性一直是业务落地的核心痛点。为解决“如何让AI严格遵循预设逻辑生成答案”的问题&…...
深入解析Shim在跨版本API兼容中的实战应用
1. 什么是Shim技术 第一次听到"Shim"这个词是在调试一个Flink连接Hive的项目时。当时Hive版本从2.3升级到3.1,本以为要重写大量代码,结果同事说"加个Shim就行了"。这种"神奇胶水"般的技术让我印象深刻。 Shim本质上是一种…...
MusePublic圣光艺苑惊艳案例:基于真实建筑数据生成文艺复兴城市图景
MusePublic圣光艺苑惊艳案例:基于真实建筑数据生成文艺复兴城市图景 1. 引言:当古典建筑遇见AI画笔 想象一下,你手头有一份欧洲某座历史名城的建筑测绘数据,里面记录了数百座教堂、广场和宫殿的精确尺寸与风格特征。过去&#x…...
PCB数据处理利器:从安装到实战的全方位指南
PCB数据处理利器:从安装到实战的全方位指南 【免费下载链接】pcb-tools Tools to work with PCB data (Gerber, Excellon, NC files) using Python. 项目地址: https://gitcode.com/gh_mirrors/pc/pcb-tools 1. 项目价值解析 PCB Tools作为一款专注于印制电…...
交易数据一致性保障:大数据环境下的挑战
交易数据一致性保障:大数据环境下的挑战 1. 引入与连接:数字世界的"货币守卫" 想象一下:当你在电商平台下单支付后,银行显示扣款成功,但商家却显示支付失败;或者在股票交易中,你看到的股价与实际成交价格存在差异。这些看似微小的数据不一致,可能导致企业声…...
RPA-Python与pytest-microsoftgraph-python-sdk集成:pytest-microsoftgraph-python-sdk测试自动化
RPA-Python与pytest-microsoftgraph-python-sdk集成:pytest-microsoftgraph-python-sdk测试自动化 【免费下载链接】RPA-Python Python package for doing RPA 项目地址: https://gitcode.com/gh_mirrors/rp/RPA-Python RPA-Python是一款强大的Python RPA工具…...
HTML2Canvas终极指南:快速将网页内容转为精美图片的完整方案
HTML2Canvas终极指南:快速将网页内容转为精美图片的完整方案 【免费下载链接】html2canvas Screenshots with JavaScript 项目地址: https://gitcode.com/gh_mirrors/ht/html2canvas HTML2Canvas是一款强大的JavaScript库,能够直接在浏览器中把网…...
nlp_structbert_sentence-similarity_chinese-large实战教程:本地知识库向量化检索完整指南
nlp_structbert_sentence-similarity_chinese-large实战教程:本地知识库向量化检索完整指南 你是不是经常遇到这样的问题:面对公司内部堆积如山的文档、产品手册、客服记录,想找某个特定信息时,却像大海捞针一样困难?…...
手把手教你学Simulink——基于Simulink的同步整流Buck变换器效率提升仿真
目录 手把手教你学Simulink——基于Simulink的同步整流Buck变换器效率提升仿真 摘要 一、背景与挑战 1.1 传统二极管整流的效率瓶颈 1.1.1 二极管损耗机理 1.2 同步整流的优势与挑战 1.2.1 同步整流原理 1.2.2 核心挑战 1.3 设计目标 二、系统架构与…...
粒子追踪模拟单透镜聚焦comsol ansys Fluent 二维三维模型 仿真模型,文献复现
粒子追踪模拟单透镜聚焦comsol ansys Fluent 二维三维模型 仿真模型,文献复现,热湿传递在实验室折腾粒子追踪仿真的时候,最让人上头的莫过于单透镜聚焦的场景搭建。COMSOL和ANSYS这对冤家各有各的脾气——前者把物理场耦合玩出花࿰…...

