C++·模板进阶

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. 出现模板编译错误时,报错信息会非常混乱,不易定位错误

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

tk Text文本框赋值,清空

import tkinter as tk# 创建主窗口 root tk.Tk() root.title("文本框内容赋值示例")# 创建一个Text小部件 text_area tk.Text(root, height10, width50) text_area.pack()# 将内容赋值给Text小部件 text_area.insert(tk.END, "这是文本框中的内容。\n")#…

STL--栈(stack)

stack 栈是一种只在一端(栈顶)进行数据插入(入栈)和删除(出栈)的数据结构,它满足后进先出(LIFO)的特性。 使用push(入栈)将数据放入stack,使用pop(出栈)将元素从容器中移除。 使用stack,必须包含头文件: #include<stack>在头文件中,class stack定义如下: namespace std…

前端面试题33(实时消息传输)

前端实时传输协议主要用于实现实时数据交换&#xff0c;特别是在Web应用中&#xff0c;它们让开发者能够构建具有实时功能的应用&#xff0c;如聊天、在线协作、游戏等。以下是几种常见的前端实时传输协议的讲解&#xff1a; 1. Short Polling (短轮询) 原理&#xff1a;客户…

k8s record 20240705

k8s 安全管理 request 是1g&#xff0c;你得不到要求&#xff0c;我就不创建了&#xff0c;这就是准入控制二次校验 SA就是serviceAccount。 内部是SA和 token, 外部用户进来就是 .kube/config文件 namespace下的是role&#xff0c;整个集群是 ClusterRole. 动作就是Binding li…

一文带你彻底搞懂什么是责任链模式!!

文章目录 什么是责任链模式&#xff1f;详细示例SpingMVC 中的责任链模式使用总结 什么是责任链模式&#xff1f; 在我们日常生活中&#xff0c;经常会出现一种场景&#xff1a;一个请求需要经过多个对象的处理才能得到最终的结果。比如&#xff0c;一个请假申请&#xff0c;需…

集训 Day 2 模拟赛总结

复盘 7&#xff1a;30 开题 想到几天前被普及组难度模拟赛支配的恐惧&#xff0c;下意识觉得题目很难 先看 T1&#xff0c;好像不是很难&#xff0c;魔改 Kruskal 应该就行 看 T2 &#xff0c;感觉很神奇&#xff0c;看到多串匹配想到 AC 自动机&#xff0c;又想了想 NOIP …

【开源】基于RMBG的一键抠图与证件照制作系统【含一键启动包】

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

优秀策划人必逛的地方,你不会还不知道吧?

道叔今天依然记得当初刚入行的时候&#xff0c;每天为完成策划任务&#xff0c;焦虑的整晚睡不着觉的痛苦。 但其实……很多时候&#xff0c;选择比努力更重要 优秀的策划和文案&#xff0c;也从来不是天生&#xff0c;你要走的路&#xff0c;前人都已经走过,你要做的仅仅是整…

【计算几何】凸包问题 (Convex Hull)

【计算几何】凸包问题 (Convex Hull) 引言 凸多边形 凸多边形是指所有内角大小都在 [ 0 , π ] [0,π] [0,π]范围内的简单多边形 凸包 在平面上能包含所有给定点的最小凸多边形叫做凸包。 其定义为&#xff1a;对于给定集合 X&#xff0c;所有包含 X 的凸集的交集 S 被称…

QT文件生成可执行的exe程序

将qt项目生成可执行的exe程序可按照以下步骤进行&#xff1a; 1、在qt中构建运行生成.exe文件&#xff1b; 2、从自定义的路径中取出exe文件放在一个单独的空文件夹中&#xff08;exe文件在该文件夹中的release文件夹中&#xff09;&#xff1b; 3、从开始程序中搜索qt&#xf…

Python入门 2024/7/8

目录 数据容器 dict(字典&#xff0c;映射) 语法 定义字典字面量 定义字典变量 定义空字典 从字典中基于key获取value 字典的嵌套 字典的常用操作 新增元素 更新元素 删除元素 清空字典 获取全部的key 遍历字典 统计字典内的元素数量 练习 数据容器的通用操作…

运维锅总详解设计模式

本首先简介23种设计模式&#xff0c;然后用Go语言实现这23种设计模式进行举例分析。希望对您理解这些设计模式有所帮助&#xff01; 一、设计模式简介 设计模式是软件设计中用于解决常见设计问题的一套最佳实践。它们不是代码片段&#xff0c;而是解决特定问题的通用方案。设…

(图文详解)小程序AppID申请以及在Hbuilderx中运行

今天小编给大家带来了如何去申请APPID&#xff0c;如果你是小程序的开发者&#xff0c;就必须要这个id。 申请步骤 到小程序注册页面&#xff0c;注册一个小程序账号 微信公众平台 填完信息后提交注册 会在邮箱收到 链接激活账号 确认。邮箱打开链接后&#xff0c;会输入实…

线程并发库复习

1.进行和线程 什么是进程&#xff1a;进程是内存分配的基本单位&#xff0c;它是程序执行时的一个实例&#xff0c;会被放到进程就绪队列&#xff0c;等进程调度器选择它&#xff0c;给它时间片&#xff0c;它才会运行。在java中启动进程&#xff0c;main&#xff0c;test&…

14-54 剑和诗人28 - 用于实时嵌入查找的向量检索

介绍 LLM 成功的关键因素是向量嵌入的使用。通过将文本转换为数字向量表示&#xff0c;我们可以将语义含义映射到数学向量空间。这使得模型能够根据向量之间的相似性在语言中概括模式。 随着我们的模型和数据集变得越来越大&#xff0c;高效地存储、组织和检索这些嵌入变得至关…

STM32智能交通灯控制系统教程

目录 引言环境准备智能交通灯控制系统基础代码实现&#xff1a;实现智能交通灯控制系统 4.1 数据采集模块 4.2 数据处理与控制算法 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;交通灯管理与优化问题解决方案与优化收尾与总结 1. 引言 智能交通灯控…

【UE5】仅修改结构体的若干个数据

蓝图中的结构体变量 | 虚幻引擎4.27文档 (unrealengine.com) 连线连到傻&#xff0c;因为如果某个变量set空值也一起过去了。一查发现有这个节点。

Kubernetes 为pod指定DNS

在k8s里面&#xff0c;默认创建pod会给pod默认分配一个默认的dns&#xff0c;这个dns是哪来的呢&#xff1f;可不可以改成其他的dns呢&#xff1f; 先进入到pod里面来&#xff0c;可以看到这里面默认设置的DNS服务器&#xff0c;这个服务器地址为10.96.0.10。这个地址是k8s自动…

Qt入门(二):Qt的基本组件

目录 Designer程序面板 1、布局Layout 打破布局 贴合窗口 2、QWidget的属性 3、Qlabel标签 显示图片 4、QAbstractButton 按钮类 按钮组 5、QLineEdit 单行文本输入框 6、ComboBox 组合框 7、若干与数字相关的组件 Designer程序面板 Qt包含了一个Designer程序 &…

【Notepad】Notepad_6.3.1 的中文版安装详情

目录 &#x1f33c;1. Notepad的认识 &#x1f33c;2. Notepad中文版安装详情 &#x1f33c;1. Notepad的认识 Notepad 是 Windows 操作系统中的一个文本编辑器程序&#xff0c;通常用于创建和编辑简单的文本文件&#xff0c;如文本文档 (.txt)。它非常轻量且功能简单&#…