C++·模板进阶

news2024/11/20 18:37:31

1. 非类型模板参数

        之前我们写的模板参数都设定class类型的,这个模板参数用来给下面的代码中的某些元素定义类型,我们管这种模板参数叫类型形参。非类型模板参数就是用一个常量作为模板的一个参数,在模板中可将该参数当作常量来使用,这种模板参数叫非类型形参

                        ​​​​​​​

        比如我们想创建一个静态的数组的类,或者说固定大小的数组的类。如果是以前的思路就是将N定义成一个宏,但是如果那样的话无法生成多个不同大小的静态数组。此时就可以借助非类型形参,定义多个任意长度的静态数组。

        非类型形参跟类型形参一样也可以给到缺省值。

       在C++20之前,只允许整形做非类型模板参数,C++20之后可以支持double、指针等其他的内置类型

        在C++库中有专门的静态数组容器,原理用到非类型模板参数

        官网资料:array - C++ Reference

                                ​​​​​​​        

        这种静态数组的容器比C语法数组的优势在于更加严格的越界检查,在使用C语法的数组的时候它的越界检查是一种抽查原理,如果越界越的很远程序就检查不到,同时不修改越界内容也会检查不到越界行为,但是在array容器中只要越界就一定当场报错。

        但是array也不是什么好东西,因为vector完全可以替代它。

2. typename的使用

        我们上一次接触typename的时候是在定义模板参数类型的时候提到过的,当时说class和typename是通用的。这里先解释一下原因,typename可以理解成是一个类型名,但不完全是,它的作用就是告诉编译器我后面跟的这个东西是一个类型名,就是说typename是类型名的类型名。

        我们看下面两段代码

        左边的代码还没什么问题,但是到了右边,当我们把它写成模板想让这个函数可以打印所有类型的vector的时候就出现了报错。

        我们知道类或模板都有一个按需实例化的规则,就是说在预处理阶段,vector<T>::const_iterator 并不会被实例化,因此编译器无法确定这个名称是类型名,还是变量名,如果是变量名的话很明显这行代码的语法就不对。因此右边这段代码就是因为这个不确定是否是类型名的原因而报错的。

        为了解决这一问题,我们将要用到 typename 告诉编译器,我后面这个是个类型名,你不用怀疑这里语法的对错了。

        ​​​​​​​        ​​​​​​​        

        当然,还有一种更加便捷的解决办法:

        ​​​​​​​        ​​​​​​​        

        直接用 auto 代替那一大堆,因为auto一定是一个类型名,后面语句的返回值是什么类型,auto就会控制这个 it 变量是什么类型。

3. 模板的特化

3.1 概念

        通常说,使用模板可以实现一些与类型无关的代码,但对于一些特殊的类型,就可能会出现错误,此时就需要将模板特化进行处理

        ​​​​​​​        ​​​​​​​        ​​​​​​​

        比如上面这段代码日期类之间的比较可以通过调用其成员函数进行比对,但是当想通过两个日期对象的地址进行二者内容上的大小比较时就出现问题了,因为这样些less函数之间比较的是二者地址上的大小,而不是地址中内容的大小。

        此时就要对模板进行特化。即:在原模板的基础上,针对特殊类型所进行特殊化的实现方式。模板特殊化中分为函数模板特化与类模板特化

3.2 函数模板特化

        先有一个基础的函数模板,然后再写一个template,函数名后面跟一对尖括号,其中指定需要特化的类型。

        函数形参表必须要和模板函数的基础参数类型保持一致,否则会出现错误。

        ​​​​​​​        ​​​​​​​        

        这么写坑很多,函数形参的类型const的位置等问题很不好把控,所以推荐用直接写函数来代替函数模板,因为当同名函数和函数模板同时存在的时候,编译器会根据参数类型去匹配贴合度更高的一方。

        ​​​​​​​        ​​​​​​​          

        函数重载这种实现方法简单明了,代码可读性高,容易书写,因此函数模板不建议特化。

3.3 类模板特化

3.3.1 全特化

        全特化就是将模板参数列表中的参数全部都确定化

        ​​​​​​​        ​​​​​​​        

        可以看到,通过控制实例化时的模板参数类型,在实例化d2的时候调用的就是全特化模板,这中模板的特化操作很类似于函数的重载

3.3.2 偏特化

        针对模板参数的其中一部分进行特化,或者进行进一步的筛选控制

        ​​​​​​​        

        上面这段代码中只限制了第二个模板参数的类型,只要第二的模板参数的类型是int型,那么就会被特殊处理

        ​​​​​​​        

        这种特化方案的限制范围更加宽泛,只要两个模板参数都是指针那么就进行特殊化处理。

        在指定为指针特化的时候有一个值得注意点

        

        可以看到T1和T2的类型并不是指针。这个规则对于特化引用等场景时也通用。

4. 模板的分离编译

        我们之前提到过写模板的时候无论是类模板还是函数模板都要把声明和定义写到一个文件中去,下面就浅析一下原因。

        对于一个普通的函数func来说,声明定义分离后在别的文件中想调用这个func函数,那么就会在该文件中包含func函数所在的声明文件。此时这个别的文件就会拥有func函数的声明,通过这个声明可以在符号表中找到func函数的真实地址,从而调用这个函数。

        但是对于一个模板函数来说,它是模板,并不是函数,因此这个东西并没有真实的地址,所以在别的文件中包含了模板的声明,也无法对应到真实的函数地址,从而导致链接错误。

        不过这一问题有解决办法,就是在模板定义的位置显示实例化。

        ​​​​​​​        

        这样就相当于可以在编译阶段告诉编译器,我后面会将这个模板实例化成 int 和 double 因此就不会出现找不到对应函数而产生的链接错误了。

        当然,最推荐的还是直接把函数模板实现写在 .h 文件中,这样也避免了各种问题

        类模板的声明和定义也是都要写在一个文件中,但是因为类模板的成员函数可能比较长,因此可以把类模板中的成员函数实现在类模板外面,把成员函数的声明放在类模板里面,但是成员函数的定义也要与类模板保持在同一文件中。

        如果把成员函数直接写在类模板中,这个函数就成为了一个内联函数inline

        

5. 模板总结

        优点:

                1. 模板复用了代码,节省资源,可以更快的迭代开发,C++的标准模板库(STL)因此产生。

                2. 增强了代码的灵活性

        缺点:

                1. 模板会导致代码膨胀问题,也会导致编译时间边长

                2. 出现模板编译错误时,报错信息会非常混乱,不易定位错误

        但总的来说模板的弊端都是我们可以接受的,模板这个东西还是一个非常好的发明。

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

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

相关文章

RT2-使用NLP的方式去训练机器人控制器

目标 研究在网络数据上训练的视觉语言模型也可以直接结合到端到端的机器人控制中&#xff0c;提升泛化性以及获得突出的语义推理&#xff1b;使得单个的端到端训练模型可以同时学习从机器人观测到动作的映射&#xff0c;这个过程可以受益于基于网络上的语言和视觉语言数据的预训…

Python函数 之 函数基础

print() 在控制台输出 input() 获取控制台输⼊的内容 type() 获取变量的数据类型 len() 获取容器的⻓度 (元素的个数) range() ⽣成⼀个序列[0, n) 以上都是我们学过的函数&#xff0c;函数可以实现⼀个特定的功能。我们将学习⾃⼰如何定义函数, 实现特定的功能。 1.函数是什么…

C++进阶:继承和多态

文章目录 ❤️继承&#x1fa77;继承与友元&#x1f9e1;继承和静态成员&#x1f49b;菱形继承及菱形虚拟继承&#x1f49a;继承和组合 ❤️多态&#x1fa77;什么是多态&#xff1f;&#x1f9e1;多态的定义以及实现&#x1f49b;虚函数&#x1f49a;虚函数的重写&#x1f499…

如何借助社交媒体影响者的力量,让品牌影响力倍增?

一、引言&#xff1a;为何社交媒体影响者如此关键&#xff1f; 在信息爆炸的今天&#xff0c;社交媒体已成为塑造消费者行为与品牌认知的重要渠道。社交媒体影响者&#xff0c;凭借其在特定领域的专业知识、庞大的粉丝基础及高度的互动性&#xff0c;成为了品牌传播不可忽视的…

JVM原理(二四):JVM虚拟机锁优化

高效并发是从JDK 5升级到JDK 6后一项重要的改进项&#xff0c;HotSpot虛 拟机开发团队在这个版本上花费了大量的资源去实现各种锁优化技术&#xff0c;如适应性自旋( Adaptive Spinning)、锁消除( Lock Elimination)、锁膨胀(Lock Coarsening)、轻量级锁(Lightweight Locking)、…

DeepMind的JEST技术:AI训练速度提升13倍,能效增强10倍,引领绿色AI革命

谷歌旗下的人工智能研究实验室DeepMind发布了一项关于人工智能模型训练的新研究成果&#xff0c;声称其新提出的“联合示例选择”&#xff08;Joint Example Selection&#xff0c;简称JEST&#xff09;技术能够极大地提高训练速度和能源效率&#xff0c;相比其他方法&#xff…

数字信号处理教程(3)——z变换

在连续时间域中的每一种分析方法&#xff0c;在离散时间域中想必也能得到对应一种分析方法。连续傅里叶变换对应着离散傅里叶变换&#xff08;DFT&#xff09;&#xff0c;而在拉普拉斯变换则是对应着z变换。z变换能够将信号表示成离散复指数函数的线性组合。连续傅里叶变换可以…

NAT技术及其应用

网络地址转换&#xff08;NAT&#xff0c;Network Address Translation&#xff09;是一种广泛应用于现代网络中的技术&#xff0c;旨在解决IP地址短缺问题&#xff0c;同时增强网络的安全性和灵活性。本文将详细解释NAT技术的工作原理&#xff0c;并探讨其在家庭及企业网络中的…

华为HCIP Datacom H12-821 卷30

1.单选题 以下关于OSPF协议报文说法错误的是? A、OSPF报文采用UDP报文封装并且端口号是89 B、OSPF所有报文的头部格式相同 C、OSPF协议使用五种报文完成路由信息的传递 D、OSPF所有报文头部都携带了Router-ID字段 正确答案&#xff1a;A 解析&#xff1a; OSPF用IP报…

【大模型LLM面试合集】大语言模型架构_layer_normalization

2.layer_normalization 1.Normalization 1.1 Batch Norm 为什么要进行BN呢&#xff1f; 在深度神经网络训练的过程中&#xff0c;通常以输入网络的每一个mini-batch进行训练&#xff0c;这样每个batch具有不同的分布&#xff0c;使模型训练起来特别困难。Internal Covariat…

最佳 iPhone 解锁软件工具,可免费下载用于电脑操作的

业内专业人士表示&#xff0c;如果您拥有 iPhone&#xff0c;您一定知道忘记锁屏密码会多么令人沮丧。由于 Apple 的安全功能强大&#xff0c;几乎不可能在没有密码或 Apple ID 的情况下访问锁定的 iPhone。 “当我忘记密码时&#xff0c;如何在没有密码的情况下解锁iPhone&am…

来一组爱胜品1133DN PRO打印机的照片

刚拆箱的机器正面照片 打开前盖正准备要安装原装耗材 下图是原装耗材&#xff0c;硒鼓型号是DR2833、碳粉盒型号是TN2833,鼓组件打印页数12000页&#xff0c;TN2833标准容量粉盒打印页数1600页/5%覆盖率&#xff0c;TN2833H大容量粉盒打印页数3000页/5%覆盖率、TN2833L超大容量…

【LLM】三、open-webui+ollama搭建自己的聊天机器人

系列文章目录 往期文章回顾&#xff1a; 【LLM】二、python调用本地的ollama部署的大模型 【LLM】一、利用ollama本地部署大模型 目录 前言 一、open-webui是什么 二、安装 1.docker安装 2.源码安装 三、使用 四、问题汇总 总结 前言 前面的文章&#xff0c;我们已经…

Studying-代码随想录训练营day34| 62.不同路径、63.不同路径II、343.整数拆分、96.不同的二叉搜索树

第34天&#xff0c;动态规划part02&#xff0c;牢记五部曲步骤&#xff0c;编程语言&#xff1a;C 目录 62.不同路径 63.不同路径II 343.整数拆分 96.不同的二叉搜索树 总结 62.不同路径 文档讲解&#xff1a;代码随想录不同路径 视频讲解&#xff1a;手撕不同路径 题目…

红酒知识百科:从入门到精通

红酒&#xff0c;这个深邃而迷人的世界&#xff0c;充满了无尽的知识与奥秘。从葡萄的选择、酿造工艺&#xff0c;到品鉴技巧&#xff0c;每一步都蕴藏着深厚的文化底蕴和精细的技艺。今天&#xff0c;就让我们一起踏上这场红酒知识之旅&#xff0c;从入门开始&#xff0c;逐步…

2024年7月1日,公布的OpenSSH的漏洞【CVE-2024-6387】

目录 ■概要 ■概要&#xff08;日语&#xff09; ■相关知识 openssh 和 ssh 有区别吗 如何查看 openssh的版本 漏洞描述 glibc Linux是什么 如何查看系统是不是基于 Gibc RHEL Linux 是基于Glibc的Linux吗 还有哪些 Linux版本是基于 GNU C库&#xff08;glibc&…

Github Actions 构建Vue3 + Vite项目

本篇文章以自己创建的项目为例&#xff0c;用Github Actions构建。 Github地址&#xff1a;https://github.com/ling08140814/myCarousel 访问地址&#xff1a;https://ling08140814.github.io/myCarousel/ 具体步骤&#xff1a; 1、创建一个Vue3的项目&#xff0c;并完成代…

谷粒商城 - 编写一个自定义校验注解

目录 开始 未来实现效果 第一步&#xff1a;编写自定义校验注解 第二步&#xff1a;编写自定义校验器 第三步&#xff1a;编写配置文件 效果演示 开始 未来实现效果 编写一个 ListValue 注解&#xff0c;可以实现功能有&#xff1a; 限定字段的值&#xff0c;例如指定只…

注解复习(java)

文章目录 注解内置注解**Deprecated**OverrideSuppressWarnings【不建议使用】Funcationallnterface 自定义注解元注解RetentionTargetDocumentedInherited 和 Repeatable 反射注解 前言&#xff1a;笔记基于动力节点 注解 注解可以标注在 类上&#xff0c;属性上&#xff0c…

LabVIEW中使用 DAQmx Connect Terminals作用意义

该图展示了如何在LabVIEW中使用 DAQmx Connect Terminals.vi 将一个信号从一个源端口连接到一个目标端口。这种处理有以下几个主要目的和作用&#xff1a; 同步操作&#xff1a; 在多任务、多通道或多设备系统中&#xff0c;可能需要不同的组件在同一时刻执行某些操作。通过将触…