【C++】进阶模板
模板进阶
- 一、非类型模板参数
 - 二、模板的特化
 - 1. 函数模板的特化
 - 2. 类模板特化
 - 3. 模板特化的应用
 
- 三、模板的分离编译
 - 1. 分离编译
 - 2. 模板的分离编译
 - 3. 解决方法
 
- 四、模板总结
 
我们在 初识模板 中已经初步接触过模板了,下面我们开始更进一步学习模板。
一、非类型模板参数
模板参数分类类型形参与非类型形参。
- 类型形参:出现在模板参数列表中,跟在 class 或者 typename 之类的参数类型名称。
 - 非类型形参:就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用,而且非类型模板参数只支持整型。
 
例如我们定义一个 Stack 类,我们在实例化的时候传入需要用的空间大小,这样就可以避免扩容或者空间浪费的问题了;如下:
			template <class T, size_t N>class Stack{public:Stack()	{}private:T _a[N];};int main(){Stack<int, 100> st1;Stack<double, 1000> st2;return 0;}
 
注意:
- 浮点数、类对象以及字符串是不允许作为非类型模板参数的,只支持整型。
 - 非类型的模板参数必须在编译期就能确认结果。
 
二、模板的特化
1. 函数模板的特化
函数模板的特化步骤:
- 必须要先有一个基础的函数模板
 - 关键字 template 后面接一对空的尖括号<>
 - 函数名后跟一对尖括号,尖括号中指定需要特化的类型
 - 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误
 
例如,我们要对日期类的指针进行比较,如果直接走模板生成的函数,就会按照指针的大小进行比较,但这并不是我们想要的,所以我们可以对函数模板进行特化,如下:
		// 函数模板特化// 函数模板 -- 参数匹配template<class T>bool Less(T left, T right){return left < right;}// 对Less函数模板进行特化template<>bool Less<Date*>(Date* left, Date* right){return *left < *right;}int main(){cout << Less(1, 2) << endl;Date d1(2022, 7, 7);Date d2(2022, 7, 8);cout << Less(d1, d2) << endl;Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl; // 调用特化之后的版本,而不走模板生成了return 0;}
 
2. 类模板特化
假设有一个日期类,它的原模板如下:
		template<class T1, class T2>class Data{public:Data() { cout << "Data<T1, T2>" << endl; }private:T1 _d1;T2 _d2;};
 
- 全特化
 
全特化即是将模板参数列表中所有的参数都确定化,如日期类的全特化:
		// 全特化template<>class Date<int, char>{public:Date() { cout << "Date<int, char>" << endl; }};
 
我们实例化两个对象,分别调用原模板和全特化模板:

- 偏特化
 
偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。比如对于上面的日期类原模板。
偏特化有以下两种表现方式:
- (1)部分特化:将模板参数类表中的一部分参数特化。
 
例如:
			// 偏特化1.// 将第二个参数特化为inttemplate <class T1>class Date<T1, int>{public:Date() { cout << "Date<T1, int>" << endl; }};
 
- (2)参数更进一步的限制
 
偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本。
例如:
		// 偏特化2.// 两个参数偏特化为指针类型template <class T1, class T2>class Date <T1*, T2*>{public:Date() { cout << "Date<T1*, T2*>" << endl; }};
 
我们分别针对两种偏特化的模板实例化对象,如下:

我们可以看到,编译器确实调用了特化的 int 版本和特化的指针版本。
如果有多个模板符合实例化的对象,编译器会选择最优的那一个进行实例化。
3. 模板特化的应用
假如有如下专门用来按照小于比较的类模板 Less:
		template<class T>struct Less{bool operator()(const T& x, const T& y) const{return x < y;}};
 
我们实例化出几个对象,并将它们放入 vector<Date> 中进行排序:
		int main(){Date d1(2023, 10, 7);Date d2(2023, 10, 6);Date d3(2023, 10, 8);vector<Date> v1;v1.push_back(d1);v1.push_back(d2);v1.push_back(d3);// 可以直接排序,结果是日期升序sort(v1.begin(), v1.end(), Less<Date>());return 0;}
 
我们以上的方法是可以直接排序的,但是现在我们要将 d1、d2、d3 的地址放入 vector<Date*> 中呢?例如:
		int main(){Date d1(2023, 10, 7);Date d2(2023, 10, 6);Date d3(2023, 10, 8);vector<Date*> v2;v2.push_back(&d1);v2.push_back(&d2);v2.push_back(&d3);// 不能直接排序,结果是错误的sort(v2.begin(), v2.end(), Less<Date*>());return 0;}
 
如果我们还是以上面的小于比较的类模板进行排序,结果是错误的,因为按照上面的比较方法比较的是地址,而地址的大小每次传入是不一样的,所以每一次比较的大小都是不一样的;所以我们可以对 Less 类模板按照指针的方式特化,如下:
		// 对Less类模板按照指针方式特化template<>struct Less<Date*>{bool operator()(Date* x, Date* y) const{return *x < *y;}};
 
特化之后,在运行上述代码,就可以得到正确的结果。
三、模板的分离编译
1. 分离编译
一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链接起来形成单一的可执行文件的过程称为分离编译模式。
2. 模板的分离编译
假如有以下场景,模板的声明与定义分离开,在头文件中进行声明,源文件中完成定义:
		// a.htemplate<class T>T Add(const T& left, const T& right);// a.cpptemplate<class T>T Add(const T& left, const T& right){return left + right;}// main.cpp#include"a.h"int main(){Add(1, 2);Add(1.0, 2.0);return 0;}
 
C/C++ 程序要正常运行,一般要经过以下步骤:预处理 --> 编译 --> 汇编 --> 链接。
在 a.cpp 中,编译器没有看到对 Add 模板函数的实例化,因此不会生成具体的加法函数。
在链接阶段,编译器会将多个obj文件合并成一个,并处理没有解决的地址问题;而在 main.obj 中调用的 Add< int > 和 Add< double > ,编译器在链接时才会找其地址,但是这两个函数没有实例化没有生成具体代码,因此链接时报错。
3. 解决方法
- 将声明和定义放到一个文件 “xxx.hpp” 里面或者 “xxx.h” 其实也是可以的,推荐使用这种。
 - 模板定义的位置显式实例化。这种方法不实用,不推荐使用。
 
四、模板总结
【优点】
- 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
 - 增强了代码的灵活性
 
【缺陷】
- 模板会导致代码膨胀问题,也会导致编译时间变长
 - 出现模板编译错误时,错误信息非常凌乱,不易定位错误
 
相关文章:
【C++】进阶模板
模板进阶 一、非类型模板参数二、模板的特化1. 函数模板的特化2. 类模板特化3. 模板特化的应用 三、模板的分离编译1. 分离编译2. 模板的分离编译3. 解决方法 四、模板总结 我们在 初识模板 中已经初步接触过模板了,下面我们开始更进一步学习模板。 一、非类型模板…...
易点易动设备管理系统:打通采购管理的智能化设备管理解决方案
在现代企业的运营中,设备管理是一个关键的环节。传统的设备管理方法往往效率低下,导致设备故障频发、巡检和维修工作不协调,备件管理不规范。为了解决这些问题,我们引入了易点易动设备管理系统,它能够全面管理设备的生…...
成集云 | 管家婆ERP集成金蝶云星辰 | 解决方案
源系统成集云目标系统  编辑 方案介绍 管家婆ERP系统是一个全面而灵活的企业资源计划平台,旨在帮助企业优化和自动化其业务流程,从而提高效率和生产力。该系统集成了从供应链管理、生产管理、财务管理到人力资源管理等所有企业运营方面的功能&#x…...
Django开发之进阶篇
Django进阶篇 一、Django学习之模板二、Django学习之中间件默认中间件自定义中间件 三、Django学习之ORM定义模型类生成数据库表操作数据库添加查询修改删除 一、Django学习之模板 在 Django 中,模板(Template)是用于生成动态 HTMLÿ…...
【C++】:类和对象(3)
朋友们、伙计们,我们又见面了,本期来给大家解读一下有关Linux的基础知识点,如果看完之后对你有一定的启发,那么请留下你的三连,祝大家心想事成! C 语 言 专 栏:C语言:从入门到精通 数…...
windows创建服务:更新服务信息乱码问题(ChangeServiceConfig)
因为小项目需要创建windows服务,安装微软官方示例一切都挺顺利,代码运行后发现配置的信息在系统里显示乱码。打开注册表发现的确是乱码。这就排除软件读取得问题,而是调用ChangeServiceConfig系统函数写入时就发生了乱码。让我在网上查找了一…...
Spark 9:Spark 新特性
Spark 3.0 新特性 Adaptive Query Execution 自适应查询(SparkSQL) 由于缺乏或者不准确的数据统计信息(元数据)和对成本的错误估算(执行计划调度)导致生成的初始执行计划不理想,在Spark3.x版本提供Adaptive Query Execution自适应查询技术,通过在”运行…...
Angular+html+js前端加载生命周期
参考:document.readyState - Web API 接口参考 | MDN (mozilla.org) 第一步,JS生命周期第一步 文档加载中状态,document.readyState loading 第二步,JS生命周期第二步 可交互状态,document.readyState interacti…...
社区投稿| 以安全视角,深度剖析 Sui Staking 与 LSD
本篇技术研报由 MoveBit 研究团队的 Jason 撰写 #1 Sui Staking 介绍 1.1 Sui 网络概述 Sui 网络由一组独立的验证者运行,每个验证者在自己的机器或集群上运行独立的 Sui 软件实例。 Sui 采用委托权益证明(DPoS)来确定哪些验证者参与网络…...
AM@邻域@极限定义中的符号说明
文章目录 abstract邻域👺邻域中心和半径去心邻域 ϵ , δ \epsilon,\delta ϵ,δ的意义各种极限定义的共同点几何意义极限定义中的极限过程临界值 ϵ \epsilon ϵ的选取👺 概念辨析👺无限接近不同于越来越接近例例 越来越接近推不出无限接近 …...
论Oracle兼容性,我们需要做什么
作者介绍:王海峰,数据库系统架构师,YashanDB SQL开发负责人,10年以上数据库内核技术开发经验。 Oracle兼容性是目前国产数据库的关键任务之一,其直接影响到商业迁移的成本和竞争力。 我们经常发现,部分国产…...
你知道多号发圈的同时并延迟评论的方式吗?
你知道多号发圈的同时并延迟评论的方式吗? 其实很简单。 步骤1:编辑好朋友圈内容 步骤2:设置延迟评论 步骤3:选择多个号发圈 通过以上3个步骤,就可以实现多号发圈的同时并延迟评论。 在发布朋友圈前,只需要…...
【BugBounty】记一次XSS绕过
前言 最近一直在看国外的赏金平台,绕waf是真的难受, 记录一下绕过的场景。 初步测试 一开始尝试XSS,发现用户的输入在title中展示,那么一般来说就是看能否闭合,我们从下面图中可以看到,输入尖括号后被转成了实体。 …...
Linux文件目录结构详解:根目录和常见子目录介绍
文章目录 引言1. 什么是Linux文件目录结构2. Linux文件系统的重要性 根目录(/)2.1 根目录的作用和特点2.2 根目录下常见目录的介绍 /bin 目录3.1 /bin 目录的作用和内容3.2 常见的可执行命令示例 /etc 目录4.1 /etc 目录的作用和内容4.2 配置文件的存放位…...
知识付费小程序的推广与用户增长策略
在知识付费小程序开发完成后,推广和用户增长是关键的成功因素。本文将探讨一些推广策略和用户增长方法,并提供代码示例,帮助您在知识付费小程序中实施这些策略。 1. 社交媒体分享功能 在知识付费小程序中添加社交媒体分享功能,…...
微信小程序 获取当前屏幕的可见高宽度
很多时候我们做一下逻辑 需要用整个窗口的高度或宽度参与计算 而且很多时候我们js中拿到的单位都是px像素点 没办法和rpx同流合污 官方提供了wx.getSystemInfoSync() 可以获取到部分窗口信息 其中就包括了整个窗口的宽度和高度 wx.getSystemInfoSync().windowHeight 返回值为像…...
使用 Splashtop 驾驭未来媒体和娱乐
在当今时代,数字转型不再是可选项,而是必选项。如今,媒体与娱乐业处于关键时刻,正在错综复杂的创意、技术和远程协作迷宫之中摸索前进。过去几年发生的全球事件影响了我们的日常生活,不可逆转地改变了行业的运作方式&a…...
Tomcat项目启动报错
java.io.IOException: java.lang.ClassCastException: Cannot cast org.springframework.web.SpringServletContainerInitializer to javax.servlet.ServletContainerInitializer解决办法:可能Tomcat版本不对,使用7.0.90版本启动报错,使用8.0…...
offer
【录用通知书】 如何判断公司的好坏呢。 注意了,我们软件行业,技术管理类,技术类,产品类 好公司好企业基本都会给你说清楚,一项多少钱,加班多少钱,这样的 像这类公司的薪资结构复杂就要特别…...
漏洞复现--鸿运主动安全监控云平台任意文件下载
免责声明: **文章中涉及的漏洞均已修复,敏感信息均已做打码处理,文章仅做经验分享用途,切勿当真,未授权的攻击属于非法行为!文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
【OSG学习笔记】Day 18: 碰撞检测与物理交互
物理引擎(Physics Engine) 物理引擎 是一种通过计算机模拟物理规律(如力学、碰撞、重力、流体动力学等)的软件工具或库。 它的核心目标是在虚拟环境中逼真地模拟物体的运动和交互,广泛应用于 游戏开发、动画制作、虚…...
YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
linux arm系统烧录
1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 (忘了有没有这步了 估计有) 刷机程序 和 镜像 就不提供了。要刷的时…...
sqlserver 根据指定字符 解析拼接字符串
DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
GO协程(Goroutine)问题总结
在使用Go语言来编写代码时,遇到的一些问题总结一下 [参考文档]:https://www.topgoer.com/%E5%B9%B6%E5%8F%91%E7%BC%96%E7%A8%8B/goroutine.html 1. main()函数默认的Goroutine 场景再现: 今天在看到这个教程的时候,在自己的电…...
【Post-process】【VBA】ETABS VBA FrameObj.GetNameList and write to EXCEL
ETABS API实战:导出框架元素数据到Excel 在结构工程师的日常工作中,经常需要从ETABS模型中提取框架元素信息进行后续分析。手动复制粘贴不仅耗时,还容易出错。今天我们来用简单的VBA代码实现自动化导出。 🎯 我们要实现什么? 一键点击,就能将ETABS中所有框架元素的基…...
spring Security对RBAC及其ABAC的支持使用
RBAC (基于角色的访问控制) RBAC (Role-Based Access Control) 是 Spring Security 中最常用的权限模型,它将权限分配给角色,再将角色分配给用户。 RBAC 核心实现 1. 数据库设计 users roles permissions ------- ------…...
Kubernetes 节点自动伸缩(Cluster Autoscaler)原理与实践
在 Kubernetes 集群中,如何在保障应用高可用的同时有效地管理资源,一直是运维人员和开发者关注的重点。随着微服务架构的普及,集群内各个服务的负载波动日趋明显,传统的手动扩缩容方式已无法满足实时性和弹性需求。 Cluster Auto…...
