C++模板进价

news2024/12/25 12:22:39

本期我们来学习C++模板的进价内容,没有看过初阶的同学建议先看看初阶内容

(26条消息) C++模板初阶_KLZUQ的博客-CSDN博客

目录

非类型模板参数

模板特化

函数模板特化

类模板特化

模板分离编译

模板总结


 我们之前一直说我们写模板时,typename和class没什么区别,所以下面我们就来看一个有区别的例子

我们这里有一段输出的代码,如果我们想要一个可以针对各种容器使用的print该怎么办呢?

所以我们想到了模板

但是我们写出来后发现编译不通过

 我们要在这里加一个typename,不能用class

编译器从上往下走,container没有实例化,编译器是不知道他是什么类型的,我们之前是明确告诉它是vector<int>类型,vector<int>已经被实例化,去vector<int>实例化出来的类里就能找到const_iterator,而container这里是不知道的,那此时就有两种可能,一种就是这里是静态成员变量,或者对象,因为静态成员可以直接由类域去访问,所以const_iterator可能是类里面的静态成员,也有可能是container里typedef的,或者是内部类,也就是说,Container::const_iterator到底是类型还是对象,这里分不清,所以要求在这里加一个typename,告诉这里就是一个类型

如果大家注意的话,这里也是一样的情况

只要取类模板里面的内嵌类型,类模板没有实例化,就不能区分,就要加typename

非类型模板参数

模板参数分类类型形参与非类型形参
类型形参即:出现在模板参数列表中,跟在 class 或者 typename 之类的参数类型名称
非类型形参,就是用一个常量作为类 ( 函数 ) 模板的一个参数,在类 ( 函数 ) 模板中可将该参数当成常量来使用
有些场景我们是需要使用非类型形参的

比如这里,假设我们定义了静态栈,st1我们要存10个数据,但是st2我们要存100个数据,该怎么办?

所以我们就引入了非类型模板参数,这样就可以解决问题

这里的N一定是常量

是不能修改的

还有一个点,这里如果不调用就不会报错,不同编译器下可能不一样,有的编译器可能会报错

这里是按需实例化 ,意思是这个函数如果没有调用,就不生成它的指令,也就不会去检查他的语法,也就是调用了才会去实例化

我们回过头来继续看,非类型模板参数的限制非常多

首先,必须是常量,然后必须是整形

 (另外,char是整形家族的,这点要牢记)

 array是一个定长数组,这里就使用了非类型模板参数

它和C语言的数组没啥区别 ,一样不能初始化,这东西还是C++11更新出来的(所以一直有人骂C++委员会,他们一直在摸鱼)

如果要说array的作用,大概只有检查越界了 

array对于越界的检查非常严格,它是一个operator[ ] 的调用,越界读写都能检查

而普通数组不能检查越界读,少部分越界写可以检查

不过还是没什么用

我们直接用vector更好,一样可以检查越界,而且还能初始化 

模板特化

函数模板特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结 果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板

 

 我们先写一个比较大小的代码

我们再传ab的地址过去,但是我们不想按地址比较,而是按数据大小比较该怎么办?

 

我们就可以使用函数模板的特化,如果是普通类型,我们就走类模板实例化,如果是int*类型就走特化

 

不过具体类型的话直接写成函数构成重载更好一点

但如果我们不仅仅想解决int*问题,我们是想解决所有指针问题呢?

 我们可以这样解决

函数模板的特化我们一般使用重载就可以解决,这个我们了解即可

类模板特化

 假设我们有一个data类,我们要对<int,double>类型进行特殊处理该怎么?

这时候我们就可以写一个特化

我们在这个特化的类里随意修改,不会影响原来的类

 我们下面来看一个应用场景

 这是我们之前的优先级队列,正常的数据正常存进去就可以,但是我们要存一个Date*,它的后面就要写很多内容 ,比较大小我们希望使用我们自己的LessDate去比较

也就是我们写成这样就可以直接用LessDate去比较,而不用写后面的内容 

  我们就可以对less进行特化,从而解决问题

 

再看看我们的普通版 ,特化的本质就是编译器的匹配原则,符合条件就走一个特殊化处理

特化必须要有原模版,这里我们写的叫做全特化,我们还可以半特化(偏特化)

第一个参数可以随便选,第二个如果是double,会走下面的,否则还是走原来的

 

我们把两种特化都写上

偏特化除了可以特化部分参数,还可以对某些类型进行限制

 比如这里,无论是什么类型,只要是两个指针就会进行匹配 

再看我们的Less,我们就可以改成这样的,只要是指针 ,就解引用去比较

库里面也有使用特化的场景,也有自己独特的价值

还可以在传引用时特化 ,指针和引用混在一起的也可以

模板分离编译

什么是分离编译?

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。

我们之前模拟实现的string,vector,list等等声明和定义是在一起的,而我们之前在C语言时写代码经常会声明和定义在两个文件里

我们以push和pop为例

 

我们将声明和定义分离

然后出现了链接错误

 

可是我们调用size缺没有问题 

 链接错误是通过了编译,在符合表里找不到地址,这是什么原因呢?

我们在.h文件里加一个A类

 

然后在.c里写出func1

 

 

我们调用func1是没问题的,但是func2就有问题了

 原因就是在call的时候可以找到func1,找不到func2

我们之前说过,在链接之前是单交互的

我们有这三个文件 ,会先预处理,预处理会进行头文件替换,预处理之后就没有头文件了,会生成.i文件,然后经过编译生成.s文件

这里的.h文件会被拷贝过来

有函数的定义才有函数的地址,所以size的地址在编译的时候,生成汇编时,在.s文件就确定了

而在.h里,除了size,像func1,func2,push,pop他们都是声明,没有定义,所以在编译阶段都没有地址

然后到了汇编,会生成.o文件,在经过链接,会将stack.o和test.o合并在一起,此时我们就发现,在编译完成时,push,pop,fun1和fun2的地址都是没有确认的,但是编译过了,这是因为是他们都有声明,声明是一种承诺,编译检查的声明函数名参数返回值等等都可以对上,所以就会等着链接的时候,拿着修饰后的函数去其他文件的符号表查找

这里就有问题了,func1查到了,所以链接过了,但是func2链接查不到,因为func2我们没有定义,这些我们都可以理解,然后就是push,push链接查不到,可是push我们是定义的,这是什么情况?

我们再看这几个文件,有声明有定义,但是单有一个定义,是不能生成地址的,因为这里连T是什么都不知道

我们知道最后这里会被各种修饰,变为pushi什么什么的 ,拿着pushi去前面到处找,是确实找不到的,.o文件里找不到的,没有生成地址,因为没有实例化,func1为什么可以呢?因为func1不是模板,它可以生成地址,涉及模板的,只有实例化才能生成地址

举个例子,假设我们买房,然后我们的钱在银行存的是死期,于是我们用信用卡套了几万块钱,当我们把钱转给开发商时,被银行拦截下来,告诉我们借贷的钱不能用来入市,这里就存在一个信息差,银行知道,而我们不知道,所以我们的代码也是一样的

这里的一个解决办法就是显示实例化 ,但是这种方式是不好的

这种方法治标不治本

 

除非我们再加一个,但是这样太麻烦了,用一个就要加一个

 这里还有更好的办法,大家先想想为什么我们调用size没事

是因为size不需要去链接的时候找,其他类型是因为只有声明,而size的声明和定义在一起,所以最后在test.cpp里它知道自己要实例化成什么,而且他有定义,就会实例化,可以找到

所以想要声明和定义分离的话,在一个文件声明和定义分离就行了,stl里也是这么做的

这是stl的list,对于小函数,这种几行就能写完的,它的定义就在类里面,成了内联

而大一点的在类外面,不过他们还是在同一个文件里 ,而不是分离成两个文件

有些人会将声明和定义的文件改为xxx.hpp,就是.h和.cpp合在一起的意思

 比如boost就是这样做的,当然定义为.h也可以,这只是名字的暗示,根据喜好选择即可

模板总结

【优点】
1. 模板复用了代码,节省资源,更快的迭代开发, C++ 的标准模板库 (STL) 因此而产生
2. 增强了代码的灵活性
【缺陷】
1. 模板会导致代码膨胀问题,也会导致编译时间变长
2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

以上即为本期全部内容,希望大家可以有所收获

如果错误,还请指正 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FPGA2-采集OV5640乒乓缓存后经USB3.0发送到上位机显示

1.场景 基于特权A7系列开发板&#xff0c;采用OV5640摄像头实时采集图像数据&#xff0c;并将其经过USB3.0传输到上位机显示。这是验证数据流能力的很好的项目。其中&#xff0c;用到的软件版本&#xff0c;如下表所示&#xff0c;基本的硬件情况如下。该项目对应FPGA工程源码…

【雕爷学编程】Arduino动手做(129)---TTS文字转语音合成模块2

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

【iOS】KVC KVO 总结

文章目录 KVC1. KVC赋值原理 setValue:forKey:2. KVC取值原理 valueForKey:3. 注意4. KVC的批量存值和取值 KVO 使用1. KVO的介绍2. KVO监听的步骤注册监听监听实现移除监听例子 3. KVO的传值4. KVO注意5. KVO的使用场景 KVO原理1. KVO的本质是改变了setter方法的调用2. _NSSet…

【图论】树上差分(边差分)

一.简介 其实点差分和边差分区别不大。 点差分中&#xff0c;d数组存储的是树上的节点 边差分中&#xff0c;d数组存储的是当前节点到父节点的那条边的差分值。 指定注意的是&#xff1a;边差分中因为根连的父节点是虚点&#xff0c;所以遍历结果时应当忽略&#xff01; 二…

西安科技大学:融合传统与创新的学府之旅

文章目录 一、引言二、历史与发展三、学校特色四、学科建设五、校园环境与设施六、合作交流七、未来发展与展望 一、引言 西安科技大学历史悠久&#xff0c;底蕴深厚。学校办学历史可以追溯到1895年成立的北洋大学工学院采矿冶金科&#xff0c;1938年迁并于西北工学院矿冶系&a…

网络编程、网络编程的三要素、TCP/UDP通信、三次握手和四次挥手

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaweb 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 网络编程 一、初始网络编程1.1什么是网络编程1.2BS/CS的优…

时序预测 | MATLAB实现NARX-ANFIS时间序列预测

时序预测 | MATLAB实现NARX-ANFIS时间序列预测 目录 时序预测 | MATLAB实现NARX-ANFIS时间序列预测效果一览基本介绍研究内容程序设计参考资料效果一览

JS判断类型的方法和对应的局限性(typeof、instanceof和Object.prototype.toString.call()的用法)

JS判断类型的方法和对应的局限性(typeof、instanceof和Object.prototype.toString.call()的用法&#xff09; 一、typeof 返回&#xff1a; 该方法返回小写字符串表示检测数据属于什么类型&#xff0c;例如&#xff1a; 检测函数返回function 可判断的数据类型&#xff1a…

【程序员面试金典】02.07. 链表相交

题目 解题思路 Code Java public ListNode getIntersectionNode(ListNode headA, ListNode headB) {if (headA null || headB null) return null;ListNode a headA;ListNode b headB;while (a ! b ) {a a ! null ? a.next : headB; b b ! null ? b.next : headA; …

MD-MTSP:成长优化算法GO求解多仓库多旅行商问题MATLAB(可更改数据集,旅行商的数量和起点)

一、成长优化算法GO 成长优化算法&#xff08;Growth Optimizer&#xff0c;GO&#xff09;由Qingke Zhang等人于2023年提出&#xff0c;该算法的设计灵感来源于个人在成长过程中的学习和反思机制。学习是个人通过从外部世界获取知识而成长的过程&#xff0c;反思是检查个体自…

cmake 配置Visual studio的调试命令

配置代码如截图&#xff1a; set_property(TARGET ${TARGET_NAME} PROPERTY VS_DEBUGGER_COMMAND "./consoleTest.exe") set_property(TARGET ${TARGET_NAME} PROPERTY VS_DEBUGGER_COMMAND_ARGUMENTS "./config/labelDriver.cfg") set_propert…

【LeetCode每日一题】——84.柱状图中最大的矩形

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 栈 二【题目难度】 困难 三【题目编号】 84.柱状图中最大的矩形 四【题目描述】 给定 n 个…

【LeetCode】142.环形链表Ⅱ

题目 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部…

WPF线程使用详解:提升应用性能和响应能力

在WPF应用程序开发中&#xff0c;线程的合理使用是保证应用性能和响应能力的关键。WPF提供了多种线程处理方式&#xff0c;包括UI线程、后台线程、Task/Async Await和BackgroundWorker。这些方式与传统的Thread类相比&#xff0c;更加适用于WPF框架&#xff0c;并能够简化线程操…

RTPSv2.2(中文版)

实时发布订阅协议 &#xff08;RTPS&#xff09; DDS互操作性 有线协议规范 V2.2 &#xff08;2014-09-01正式发布&#xff09; https://www.omg.org/spec/DDSI-RTPS/2.2/PDF 目 录 1 范围Scope 9 2 一致性Conformance 9 3 参考文献References 9 4 术语和定义Terms a…

【fly-iot飞凡物联】(12):EMQX 5.1使用docker 本地部署,接入到Actorcloud的数据库中,成功连接创建的设备,可以控制设备访问状态

目录 前言1&#xff0c;关于2&#xff0c;使用docker 进行部署3&#xff0c;配置API key 可以使用接口访问的4&#xff0c;设置客户端认证&#xff0c;连接PostgreSQL 数据连接5&#xff0c;使用客户端进行连接6&#xff0c;EMQX的API 接口地址7&#xff0c;总结 前言 本文的原…

Vue2封装自定义全局Loading组件

前言 在开发的过程中&#xff0c;点击提交按钮&#xff0c;或者是一些其它场景总会遇到Loading加载框&#xff0c;PC的一些UI库也没有这样的加载框&#xff0c;无法满足业务需求&#xff0c;因此可以自己自定义一个&#xff0c;实现过程如下。 效果图 如何封装&#xff1f; 第…

Linux安装MySQL 8.1.0

MySQL是一个流行的开源关系型数据库管理系统&#xff0c;本教程将向您展示如何在Linux系统上安装MySQL 8.1.0版本。请按照以下步骤进行操作&#xff1a; 1. 下载MySQL安装包 首先&#xff0c;从MySQL官方网站或镜像站点下载MySQL 8.1.0的压缩包mysql-8.1.0-linux-glibc2.28-x…

获评最高级别权威认证!融云通过中国信通院「办公即时通信软件安全能力」评测

点击报名 8 月 3 日&#xff08;周四&#xff09;融云直播课~ 近期&#xff0c;融云再获权威认可&#xff0c;旗下百幄智能在线办公套件平台正式通过中国信通院“办公即时通信软件安全能力”测评&#xff0c;并获得最高级别“卓越级”证书。关注【融云 RongCloud】&#xff0c;…

郑州申请IP地址https证书怎么收费

IP地址https证书是为只有公网IP地址的网站准备的数字证书&#xff0c;和域名SSL证书一样IP地址https证书也为IP地址网站提供传输信息加密服务以及身份认证服务&#xff0c;而IP地址申请https证书是按照IP地址的数量进行收费的&#xff0c;IP地址越多&#xff0c;需要申请IP地址…