C++——模板进阶

作者:几冬雪来

时间:2023年10月18日

内容:C++——模板进阶讲解

目录

前言:

模板(进阶): 

typename和class特殊场景:

非类型模板参数: 

array(使用非类型模板参数):

模板的特化: 

模板的分离编译:

模板总结: 

结尾: 


前言:

在上一篇博客我们学习了反向迭代器之后,今天讲解的知识则是我们的老朋友——模板。但是并非是将原先的模板内容再讲解一遍,今天我们要了解的是模板进阶的内容。

模板(进阶): 

在一开始讲解模板的时候,我们使用模板做了许多的操作。

那个时候的模板解决了学习C++过程中的两类问题,一类是可以用它来控制容器中的数据类型。第二类就不仅仅是控制数据的类型,而是控制某种设计逻辑,比如适配器模式

也就是说,如果在代码中如果要传一个类型的话,就可以使用模板来搞定

typename和class特殊场景:

在模板中我们一般使用class和typename来定义模板,在定义模板的时候class和typename的作用是相同的

但是在某些场景下,class和typename会有一些区别所在

在这里我们简单的写了一串代码,也就是插入值和输出指的操作

但是在这个地方我们的Print却并不是那么好,因为Print里面的参数的vector类型的。如果要在写一个list类型的话,这个地方我们的Print就不能使用了

因此这里我们的思想要往泛型上靠近。

因为学习过模板的原因,在这个地方可能会有人说:这里可以和适配器一样写一个模板class Container

用Container来解决上面的问题,把原先vector<int>的位置给替换成Container

这个方法理论是可以的,但是编译器会报错

代码报错,这是因为在这个地方Container没有被实例化。在编译器中编译代码都是从上往下走的,因此编译器无法区分Container是什么类型。 

之前能成功是因为已经清楚了类型是vector<int>,它已经被实例化出来了,我们可以去实例化的类中查找和使用。 

而如上图这样子书写的话有两个地方可以使用这个语法,一个是静态成员变量,另一个是内部类,这个地方可以是类型也可能是对象

而解决这个问题的方法就是加上一个typename,在编译器中typename是类型的名称

在Container前面加上typename就是在告诉编译器这里是类型不是对象,是合乎语法的,等这个模板实例化了之后再去找

非类型模板参数: 

接下来我们来讲解一下非类型模板参数

非类型模板参数顾名思义就是不是类型的模板参数,而有的时候需要我们去使用它。

那么在什么时候非类型模板参数会被使用到呢?比如在这里我们要定义静态的栈的时候就需要使用到它

在这里我们就写了一个静态栈。

而栈的外面define了一个N,这里将它定义为10

在开空间的过程中,如果我们要开的空间的大小刚好为10的话,N就不用进行修改。但是要开100个空间的时候N就办不到了,如果N定位为100的话,只开10个空间又太浪费了

为了解决这个问题我们使用到了非类型模板参数。 

实现非类型模板参数,这个地方只需要将模板参数中加入一个size_t来代表我们要传的常量的大小即可

类似这里在下面书写的时候要开多大空间的话只需要将它的值一起写上就行了

这里还要注意一个点那就是这个地方的N因为是常量所以不能被修改的。有些编译器中N被修改了可能不会报错,这里就应该发生了按需实例化的操作。(调用了才会实例化)

非类型模板参数条件:

1.常量。

2.必须是整形。(现阶段)

同时非类型模板参数也有许多的条件限制。 

array(使用非类型模板参数):

而在C++中array(定常数组)就会用到非类型模板参数

可是在C++中array和原生数组的使用几乎一样。原生数能做到的array也能做到,但同时array也保留了一些臭毛病

比如原生数组定义的时候不会初始化,而array也不会进行初始化的操作。所以从某方面来说array非常的鸡肋。

唯一对比原生数组有优势的就是array对越界的检查非常的严格

这是因为array中重载了operator[]在operator[]中就对越界进行了检查

这也是array对比起原生数组的一个优势,但是如果数组不越界的话,那么二者的作用就是一样的没有区别。  

模板的特化: 

然后再下来讲解的是模板的特化,在C++中有时候可能要针对某些特殊化的处理,这里我们就把这个行为简称为特化

接下来就来讲解一下模板特化的场景。

在这里我们简单的写一串代码。

这个地方是通过Less进行比较左值和右值之间的大小,这里第一次比较是自己传了两个常数进行比较,第二次则是先定义初始化了a和b,再传二者的地址进行比较

第一次比较是比较二者的值,第二次比较就是比较的二者的地址

为了解决这个问题我们编译了函数特化的代码,如果要传的类型是普通类型,这里我们就走原类模板的实例化,如果是int*的指针就会优先走我们上面的代码。 

当然,这里也可以写一个现成的函数出来,与原模板构成实例化的函数重载,代码中有现成的就吃现成的。 

所以我们的函数模板可以写成特化,也可以直接书写这个函数

虽然函数模板可以直接书写函数来使用,但是类模板却没有办法,像上边就是我们一个简单的类模板。

如果这个地方要对<int,double>进行特殊化处理的话,那就只能使用特化操作了

特殊化处理要有原模板存在。

与此同时在特殊化处理中我们还分全特化和半(偏)特化

 

在这里偏特化就是不把所以的模板参数都限制死,一部分进行特化,另一部分还是用原模板的参数

同时偏特化里面还分两种特化方式

一种是特化部分参数,另外一种特化则是对类型的进一步限制

像这里就是使用了特化来对类型做了进一步的限制。在这个地方的特化T1和T2都特化为指针类型

如果下面传的是指针无论是什么类型的指针都会匹配,相反如果不是指针就不会匹配

这就是特化对类型的限制,同时特化的类相比原来的类是一个全新的类,但是它不能独立存在

模板的分离编译:

C++甚至是C语言中我们都知道声明和定义是不能被分离的,二者如果简单被分离的话会发生链接错误

类模板声明和定义也是如此

在这里要找到我们的类(Stack),但是这里我们还需要将类模板参数给传过去(T),与此同时因为这个地方没有模板参数的存在,因此还要写一个模板

接下来继续讲我们的链接错误。

链接错误就是代码在编译的时候过了,但是在发表的时候却找不到它的地址。  

接下来就来探讨为什么会出现编译错误的操作

因为一开始二者都有声明,在C语言中声明只是类似一种承诺。使用编译器检查声明函数名参数返回的时候是可以对上的,再等到链接的时候,拿着修饰后的函数去其他文件符号中查找

而且在C++中有一个方法可以解决这个问题,那就是显示实例化

在这里显示实例化,对类模板显示实例化,那么这里成员也会被显示实例化。 

但是类的类型从int变为double的话

那么为了使这种情况也可以通过,我们要将显示实例化中整形int类型给更换为double类型,这里编译器才不会报错

但是这样就会导致每新出一个这里我们就得加一个显示实例化

在模板中,它不支持直接的声明和定义分离,但是在分离编译后显示实例化是可以的

但是这个地方我们还有一种方法。

就算声明与定义分离,模板的话最好在当前文件进行声明与定义的分离

模板总结: 

最后这个地方赋上一张图来总结一下模板。

迄今为止学习到这里,我们的模板的大致学习内容就已然落幕了。

接下来我们来总结一下它的优点,有了模板以后我们写许多的代码就变得很方便了,原本应该是我们去做的事情交给了编译器去做

其次它还增加了代码的灵活性,比如适配器和仿函数

但是与此同时,它也有缺点的存在

应该就是代码膨胀的问题,因为模板要走实例化的过程,因此编译的时间会变长

而这里模板真正的缺点就是它的报错很凌乱,模板的报错正确率可能会一定程度的下降,模板提示的可信度会下降

结尾: 

到这里我们的模板进阶就已经讲解完毕了,C++所有的模板知识此刻也就正式的完结了。接下来我们将向C++更深层的知识发起进攻,最后希望这篇博客能为各位带来一些有用的帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/139434.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

检验科LIS系统,即实验室信息管理系统

LIS系统&#xff0c;即实验室信息管理系统&#xff0c;是一种基于互联网技术的医疗行业管理软件&#xff0c;它可以帮助实验室进行样本管理、检测流程管理、结果报告等一系列工作&#xff0c;提高实验室工作效率和质量。 检验科LIS系统是以计算机技术、条形码技术、串行通讯接口…

计算机工作原理

目录 ♫什么是硬件 ♫什么是软件 ♫什么是操作系统 ♫什么是进程 ♫PCB的相关属性 ♫内存管理 ♫进程间通信 ♫什么是硬件 现代计算机大多遵循冯大佬提出的冯诺依曼体系结构&#xff0c;即计算机由cup&#xff08;包括运算器和控制器&#xff09;&#xff0c;存储器&am…

竞赛 深度学习YOLO抽烟行为检测 - python opencv

文章目录 1 前言1 课题背景2 实现效果3 Yolov5算法3.1 简介3.2 相关技术 4 数据集处理及实验5 部分核心代码6 最后 1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习YOLO抽烟行为检测 该项目较为新颖&#xff0c;适合作为竞赛课…

浪涌防护:TSS管的工作原理与应用?|深圳比创达EMC

浪涌防护&#xff1a;TSS管的工作原理与应用&#xff1f;相信不少人是有疑问的&#xff0c;今天深圳市比创达电子科技有限公司就跟大家解答一下&#xff01; 一、TSS工作原理 TSS半导体放电管是一种电压开关型瞬态抑制二极管&#xff0c;即涌压抑制晶体管&#xff0c;或称为导…

Linux内核的.config 配置文件和defconfig 配置文件

Linux 内核可以通过输入“make menuconfig”来打开图形化配置界面&#xff0c;menuconfig 是一套图形化的配置工具 一、图形化界面的操作 menuconfig 图形化的配置工具需要 ncurses 库支持。ncurses 库提供了一系列的 API 函数供调用者生成基于文本的图形界面&#xff0c;因此…

Typora+PicGo+Github+CSDN梦幻联动

文章目录 一、快速搭建个人免费图床二、Typora图片实现自动上传三、Typora图片上传到CSDN出现错误 一、快速搭建个人免费图床 之前写过一篇 快速搭建个人免费图床 的文章&#xff0c;但是每次都要把图片拖到PicGo里面才能生成链接很麻烦&#xff0c;而且在本地用Typora写的文章…

【jmeter】接口测试流程

1、Jmeter简介 Jmeter是由Apache公司开发的一个纯Java的开源项目&#xff0c;即可以用于做接口测试也可以用于做性能测试。 Jmeter具备高移植性&#xff0c;可以实现跨平台运行。 Jmeter可以实现分布式负载。 Jmeter采用多线程&#xff0c;允许通过多个线程并发取样或通过独…

自动驾驶学习笔记(五)——绕行距离调试

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《2023星火培训【感知专项营】》免费课程—>传送门 文章目录 前言 调试内容 打开在线编辑器 打开pl…

广州华锐互动:VR模拟高楼层建筑应急逃生,提供身临其境的虚拟体验

随着城市化进程的不断加速&#xff0c;高层建筑越来越多地出现在我们的生活中。然而&#xff0c;高层建筑的安全问题也日益凸显。一旦发生火灾、地震等突发事件&#xff0c;如何迅速、安全地逃离高楼成为了人们关注的焦点。近年来&#xff0c;虚拟现实&#xff08;VR&#xff0…

List小练习,实现添加图书,并且有序遍历

SuppressWarnings({"all"})public static void main(String[] args) {List list new LinkedList(); // List list new Vector(); // List list new ArrayList();list.add(new Book1("红楼小梦",35.5,"曹雪芹"));list.add(new B…

Linux:Mac VMware Fusion13以及CentOS7安装包

Linux&#xff1a;Mac VMware Fusion13以及CentOS7安装包 1. Mac VMware Fusion132. CentOS7安装包3. 安装 1. Mac VMware Fusion13 下载官网地址&#xff1a;https:www.vmware.com/products/fusion/fusion-evaluation.html 2. CentOS7安装包 注意是m芯片需要使用arm架构的i…

【STM32】--基础了解

一、STM32来历背景 1.从51到STM32 &#xff08;1&#xff09;单片机有很多种 &#xff08;2&#xff09;STM32内核使用ARM&#xff0c;但是ARM不一定是STM32 &#xff08;3&#xff09;ATM32是当前主流的32位高性能单片机 &#xff08;4&#xff09;STM32的特点&#xff1a;高…