【C++】进阶模板

news2024/12/23 20:04:09

模板进阶

  • 一、非类型模板参数
  • 二、模板的特化
    • 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. 浮点数、类对象以及字符串是不允许作为非类型模板参数的,只支持整型。
  2. 非类型的模板参数必须在编译期就能确认结果。

二、模板的特化

1. 函数模板的特化

函数模板的特化步骤:

  1. 必须要先有一个基础的函数模板
  2. 关键字 template 后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
  4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误

例如,我们要对日期类的指针进行比较,如果直接走模板生成的函数,就会按照指针的大小进行比较,但这并不是我们想要的,所以我们可以对函数模板进行特化,如下:

		// 函数模板特化
		// 函数模板 -- 参数匹配
		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;
		};
  1. 全特化

全特化即是将模板参数列表中所有的参数都确定化,如日期类的全特化:

		// 全特化
		template<>
		class Date<int, char>
		{
		public:
		    Date() { cout << "Date<int, char>" << endl; }
		};

我们实例化两个对象,分别调用原模板和全特化模板:

在这里插入图片描述

  1. 偏特化

偏特化:任何针对模版参数进一步进行条件限制设计的特化版本。比如对于上面的日期类原模板。

偏特化有以下两种表现方式:

  • (1)部分特化:将模板参数类表中的一部分参数特化。

例如:

			// 偏特化1.
			// 将第二个参数特化为int
			template <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.h
		template<class T>
		T Add(const T& left, const T& right);
		
		
		// a.cpp
		template<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. 解决方法

  1. 声明和定义放到一个文件 “xxx.hpp” 里面或者 “xxx.h” 其实也是可以的,推荐使用这种。
  2. 模板定义的位置显式实例化。这种方法不实用,不推荐使用。

四、模板总结

【优点】

  1. 模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生
  2. 增强了代码的灵活性

【缺陷】

  1. 模板会导致代码膨胀问题,也会导致编译时间变长
  2. 出现模板编译错误时,错误信息非常凌乱,不易定位错误

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

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

相关文章

webservice接口自动化测试

1&#xff0c;用soupui进行测试 2&#xff0c;安装soupUI 3&#xff0c;测试的时候是给了一个wdsl 操作步诹&#xff1a;new &#xff08;name , 填写地址&#xff09;---导入wsdl文件---看到所有的接口 发送请求的格式<xml> canshu</xml> 应用场景&#xff0c…

模拟大数相加

字符串的大数相加&#xff0c;不可以直接使用stoi&#xff0c;或者stoll这种函数去相加&#xff0c;随时有可能越界。只需要模拟计算加法的过程就可以了。 1.定义两个尾指针&#xff0c;指向num1,nums2的最后一个数字&#xff0c;让这两个数字相加&#xff0c;并把相加的结果记…

使用frida来spawn Fork 的子进程

索引 需求测试程序父进程代码子进程代码 x64dbg插件功能开始调试 frida运行环境用到的文件和代码 需求 最近在学基础的Windows逆向知识&#xff0c;遇到个小问题。一个进程使用CreateProcessW创建的进程该如何在启动时附加&#xff0c;我想调试这个子进程启动时运行的函数。 …

你知道多号发圈的同时并延迟评论的方式吗?

你知道多号发圈的同时并延迟评论的方式吗&#xff1f; 其实很简单。 步骤1&#xff1a;编辑好朋友圈内容 步骤2&#xff1a;设置延迟评论 步骤3&#xff1a;选择多个号发圈 通过以上3个步骤&#xff0c;就可以实现多号发圈的同时并延迟评论。 在发布朋友圈前&#xff0c;只需要…

易点易动设备管理系统:打通采购管理的智能化设备管理解决方案

在现代企业的运营中&#xff0c;设备管理是一个关键的环节。传统的设备管理方法往往效率低下&#xff0c;导致设备故障频发、巡检和维修工作不协调&#xff0c;备件管理不规范。为了解决这些问题&#xff0c;我们引入了易点易动设备管理系统&#xff0c;它能够全面管理设备的生…

SAP内部转移价格(利润中心转移价格)的条件

SAP内部转移价格&#xff08;利润中心转移价格&#xff09; SAP内部转移价格&#xff08;利润中心转移价格&#xff09; SAP内部转移价格&#xff08;利润中心转移价格&#xff09;这个听了很多人说过&#xff0c;但是利润中心转移定价需要具备什么条件。没有找到具体的文档。…

取消加考!自考专业调整,2026年起执行新计划!

就在2023年10月7日&#xff0c;广东省教育考试院发布《关于广东省高等教育自学考试专业调整有关事项的通知》&#xff0c;自学考试迎来新变化&#xff0c;本次专业调整政策性强&#xff0c;涉及面广&#xff0c;持续时间长&#xff0c;一起来看看具体说明~ 关于广东省高等教育自…

定时任务cron,定时自动实现某段代码

定时任务表达式 组成&#xff1a;cron一般由6个空格和7个字符构成&#xff0c;七个字符按照顺序分别表示&#xff1a;秒 分 时 日 月 周 年&#xff1b;有时候“年”这个域也可以不写&#xff0c;甚至于在云函数的触发器中有这一位还会提示表达错误。 cron表达式规则&#xff1…

SpringMVC 域对象共享数据

文章目录 1、使用ServletAPI向request域对象共享数据2、使用ModelAndView向request域对象共享数据3、使用Model向request域对象共享数据4、使用map向request域对象共享数据5、使用ModelMap向request域对象共享数据6、Model、ModelMap、Map的关系7、向session域共享数据8、向app…

【编程必备知识】文件内容的读写

文章目录 前言1. 数据流2. Java IO 流3. InputStream 概述3.1 FileInputStream 概述3.1.1 代码示例 3.2 利用 Scanner 进行字符读取 4. OutputStream 概述4.1 利用 OutputStreamWriter 进行字符写入 总结 前言 书接上回, 本文继续讲解关于文件的知识, 上文讲了如何对文件系统进…

el-table合计行合并

效果如下 因为合计el-table的合并方法是不生效的,所以需要修改css下手 watch: {// 应急物资的合计合并planData: {immediate: true,handler() {setTimeout(() > {const tds document.querySelectorAll(".pro_table .el-table__footer-wrapper tr>td");tds[0]…

第二章 物理层 | 计算机网络(谢希仁 第八版)

文章目录 第二章 物理层2.1 物理层的基本概念2.2 数据通信的基础知识2.2.1 数据通信系统的模型2.2.2 有关信道的几个基本概念2.2.3 信道的极限容量 2.3 物理层下面的传输媒体2.3.1 导引型传输媒体2.3.2 非导引型传输媒体 2.4 信道复用技术2.4.1 频分复用、时分复用和统计时分复…

智能井盖传感器:数智赋能让城市管理更智慧

智能井盖传感器&#xff1a;数智赋能让城市管理更智慧 在城市化快速发展的今天&#xff0c;保护和增强城市基础设施生命线的需求至关重要。而井盖作为守护城市地下空间的安全门&#xff0c;其智能化管理与城市生命线安全工程建设息息相关。在这篇文章中将为大家详细介绍智能井…

2023年中国MarTech服务商行业发展规模及趋势分析:逐渐呈现出场景化、行业化、定制化[图]

不同赛道的市场集中度及商业模式不同&#xff0c;因此对应各细分场景的MarTech技术应用深度存在较大差异。整体来看&#xff0c;市场竞争情况激烈、产品迭代周期较快、用户互动频繁的行业在数据&策略场景、渠道运营&转化场景与客户流程&管理场景对技术的完善性及功…

漏洞复现--鸿运主动安全监控云平台任意文件下载

免责声明&#xff1a; **文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何…

想要查看员工与客户聊天记录和跟进情况,有什么工具推荐吗?

想要查看员工与客户聊天记录和每天新增客户&#xff0c;可以使用微信管理系统这个工具。 微信管理系统是一个能够同时登录多个微信&#xff0c;实现一个人管理多个微信的工具。它分为两大版块&#xff0c;一个是营销&#xff0c;一个是监管。 而监管是企业用于监管员工微信较多…

统一机器人描述格式——URDF

URDF&#xff08;Unified Robot Description Format&#xff0c;统一机器人描述格式&#xff09;是ROS中一个非常重要的机器人模型描述格式&#xff0c;ROS同时也提供URDF文件的C解析器&#xff0c;可以解析URDF文件中使用XML格式描述的机器人模型。 在使用URDF文件构建机器人模…

【算法|滑动窗口No.1】leetcode209. 长度最小的子数组

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

基于SSM的医院住院管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

物业管理智慧小区活动报名小程序开发

小程序基于UniApp开发&#xff0c;用于智慧小区物业管理&#xff0c;核心功能为业主报修、业主活动报名、房产车位管理、物业费缴费管理、线上商城等功能。 小程序深度调研物业工作场景开发而出&#xff0c;可以有效提高物业费的收缴率和帮助物业节约成本提高运营效率和提升额…