C++——模板的作用2:特例化

news2024/11/15 6:46:31

      目录

模板的形式:

一.模板的多参数应用:

例:

错误使用1:使用不标准的模板形参表

​编辑 

错误使用2:使用变量作为实参传递给函数模板

二.模板的特例化:

类模板:

针对模板的特化步骤:

类模板的全特化:

类模板的半特化:

半特化的扩展: 

三. 模板总结


          在之前,我介绍过一篇关于C++模板的作用,它的出现解决了C语言对多种不同类型的但是有着相同作用函数的难题,举个例子:想要作用于两个整型变量的交换,那么使用C语言可以写出整型交换的函数,但是又出现了char型、double型、short型变量的交换,那么就需要再写出这三个类型的交换函数,而这几个函数写出来后唯一的不同点就是返回值和形参的不同,造成了代码的冗余,可读性变差

模板的形式:

template <模板形参表>

返回值类型 函数体(模板函数形参表)

{

}

        而模板的出现使得交换函数只需要写一个就够,极大的缩减了代码,增加了函数的复用性,为泛型编程打下了坚实的基础!

(478条消息) C++基础——模板讲解_橙予清的zzz~的博客-CSDN博客https://blog.csdn.net/weixin_69283129/article/details/127845086

感兴趣的朋友门可以来看看这篇文章,它会加深你对模板的理解。 

而接下来我要讲的是模板的另外几个作用:

一.模板的多参数应用:

非类型模板参数 模板参数分类类型形参与非类型形参。

        1.类型形参即:出现在模板参数列表中,跟在class或者typename之类的参数类型名称。

        2.非类型形参,就是用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

在上面的那篇博客中,我所列举的模板例子中用到的全都是类型形参。 

 // 定义一个模板类型的静态数组
 template<class T, size_t N = 10>
 class array{
     public:
         T& operator[](size_t index){
            return _array[index];
            }
         const T& operator[](size_t index)const{
            return _array[index];
            }
 
         size_t size()const{
            return _size;
            }
         bool empty()const{
            return 0 == _size;
            }
 
     private:
         T _array[N];
         size_t _size;
         };

         通过上图代码可知:模板形参列表中出现了非类型形参。该参数可以是变量,但其类型只能是整型,这个整型包括:char、int、size_t等类型!而使用自定义类型、浮点类型的变量是不被允许的!会报编译错误!

例:

运行结果: 

错误使用1:使用不标准的模板形参表

错误使用2:使用变量作为实参传递给函数模板


二.模板的特例化:

类模板:

函数模板是对函数进行泛型的使用,让函数能够对多种类型的变量做相应的操作;

而类模板就算对类进行泛型的使用,让类中的成员变量或者函数做相应的复杂操作。

//类模板样例1:
template<class T1,class T2>
class Date {
public:
	Date() {
		cout << "模板:Date(T1,T2)" << endl;
	}
private:
	T1 _a1;
	T2 _b1;

};

针对模板的特化步骤:

1. 必须要先有一个基础的函数模板或者类模板

2. 关键字template后面接一对空的尖括号<>

3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型

4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误。 

类模板的全特化:

        全特化即是将模板参数列表中所有的参数都确定化。

//类模板的特殊化处理——全部参数特殊化处理
template<>
class Date<double,double>{
public:
	Date() {
		cout << "全特化:Date(double, double)" << endl;
	}
private:
	double _a1;
	double _b1;
};

//类模板的特殊化处理——全部参数特殊化处理2
template<>
class Date<short,char> {
public:
	Date() {
		cout << "全特化:Date(short, char)" << endl;
	}
private:
	short _a1;
	char _b1;
};

        如上,全特化的类模板所使用的模板形参列表相比较普通的类模板,类型是全部确定的。全特化的作用就是:在一般的情况下,普通的对象被创建时使用普通类模板即可,做着普通的工作。而在某种特殊情况下,我们可以让对象被创建时使用专门的经过特殊化处理的类模板,做一些特殊的操作。 

类模板的半特化:

        针对模版参数进一步进行条件限制设计的特化,即部分特化模板参数列表。

//半参数特殊化处理——案例1:
template<class T2>
class Date<double, T2> {
public:
	Date() {
		cout << "半特化:Date(double, T2)" << endl;
	}
private:
	double _a1;
	T2 _b1;
};

//半参数特殊化处理——案例2:
template<class T1>
class Date<T1, char> {
public:
	Date() {
		cout << " 半特化:Date(T1, char)" << endl;
	}
private:
	T1 _a1;
	char _b1;
};

        类模板原本是T1,T2两个类型的参数,使用半特化就是将T1具体化成double类型作为模板参数。 

int main(){
    Date<int, int> d1;
	Date<double, double>d2;	
	Date<short,char>d3;	
	Date<double, int> d4;	
	Date<int, char> d5;		
    return 0;
    }

接着,我们在main函数中使用类创建几个对象,看编译器会进入哪些类模板中!

运行结果: 

代码解析:

        通过结果可知:d1的创建是调用了类模板T1,T2的构造函数,d2,d3是调用了全特化的类模板构造函数,d4,d5调用了半特化的类模板构造函数。

        将这些比作生活的例子:当时间到了吃中午饭的时候,编译器饿了,在它面前有三种吃法:1.自己拿食材做(炒,炸,烧,爆,煎,煮);2.做省时省力的半成品饭;3.点外卖。而T1,T2类型的类模板好比是从超市买回来的新鲜食材,需要编译器自己去做才能吃;半特化的类模板好比是半成品,例如:方便面、自热饭、昨晚的剩饭剩菜,需要编译器进行小小的加工就可以吃了;而全特化的类模板好比是外卖,是现成的热乎的香喷喷的饭菜。在不考虑金钱和健不健康的情况下,我们的做法肯定是选择好吃美味而且省时省力的外卖,编译器的思想也和我们一样——有现成的就不会自己动手再去做。

        所以编译器在对d1对象的调用时,发现没有完美符合<int,int>的类模板,那么只能去自己做(使用T1,T2模板的构造函数);

        而对于d2对象的调用,发现double,double的构造函数选项有两种,一种是选择<T1,T2>的类,另一种是选择<double,double>的类,那编译器肯定是选择后者。

         ......

半特化的扩展: 

        半特化还可以应用于指针、引用的类型上!

template<class T1,class T2>
class Date<T1*,T2*> {
public:
	Date() {
		cout << "半特化:Date(T1*,T2*)" << endl;
	}
private:
	T1* _a1;
	T2* _b1;
};

//半特化4——两个参数偏特化为引用类型
template<class T1, class T2>
class Date<T1&, T2&> {
public:
	Date(const T1& d1, const T2& d2)
		: _d1(d1)
		, _d2(d2)
	{
		cout << "半特化:Data<T1&, T2&>" << endl;
	}

private:
	const T1 & _d1;
	const T2 & _d2;
};


三. 模板总结

优点:

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

 2. 增强了代码的灵活性 

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

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

相关文章

乌班图22.04安装wireguard实现异地组网

1. 前言&#xff1a; wireguard是新型的异地组网工具&#xff0c;在此之前&#xff0c;又已经被抛弃的pptp&#xff0c;l2tp&#xff0c;有配置复杂的openvpn&#xff0c;wireguard被linux作者linus赞叹优雅&#xff0c;于linux 5.6合并至linux内核主线。 2. 安装过程&#…

文心一言 VS 讯飞星火 VS chatgpt (68)-- 算法导论6.5 7题

文心一言 VS 讯飞星火 VS chatgpt &#xff08;68&#xff09;-- 算法导论6.5 7题 七、试说明如何使用优先队列来实现一个先进先出队列&#xff0c;以及如何使用优先队列来实现栈(队列和栈的定义见 10.1 节。) 文心一言&#xff1a; 优先队列是一种数据结构&#xff0c;其中…

干货|一次完整的性能测试,测试人员需要做什么?

作者介绍 邓宝菊&#xff08;Kiki Deng&#xff09;&#xff0c;10 年软件测试经验&#xff0c;4 年团队管理经验&#xff0c;当前任职研发部架构质量工程部&#xff0c;整体负责研发部测试团队的效能、工具流程建设和人才培养。 前言 一、 规范性能测试实施流程的意义 规范…

Qt: 查看qmake相关参数设置

Qt开发中&#xff0c;经常会遇到qmake相关问题&#xff0c;比如同时安装了多个Qt版本的情况。比如我的情况是系统自带了Qt 5.12.8, 但是开发中遇到一些兼容性问题&#xff0c;于是又手动安装了5.9.8。 查看qmake版本&#xff0c;qmake -v, 虽然项目中已经指定了5.9.8, 但是系统…

通过String字符生成base64编码在生成图片

* base64转图片 //对字节数组字符串进行Base64解码并生成图片 * param base64str base64码 * return // param savePath 图片路径private static final String savePath"image_ver\\verifyCode"; 判断是否为base64编码 public static void mainDD…

关闭深度学习训练/推理进程的方法

引言 设想有一种情况&#xff0c;在ssh服务器训练/推理的时候&#xff0c;突然断线&#xff0c;再次打开ssh的时候&#xff0c;发现后台在运行&#xff0c;此时无法使用 ctrlc 终止&#xff0c;从而&#xff0c;可以用一个很简单的办法来结束&#xff1a;手动关闭进程。 方法 输…

python中如何记录日志?

日志是一种可以追踪某些软件运行时所发生事件的方法。一条日志信息对应的是一个事件的发生&#xff0c;而一个事件通常需要包括以下几个内容&#xff1a;事件发生时间、事件发生位置、事件的严重程度--日志级别、事件内容。 logging模块定义的函数和类为应用程序和库的开发实现…

Python-Python基础综合案例——数据可视化 - 动态柱状图

版本说明 当前版本号[20230729]。 版本修改说明20230729初版 目录 文章目录 版本说明目录知识总览图Python基础综合案例——数据可视化 - 动态柱状图案例效果基础柱状图通过Bar构建基础柱状图反转x和y轴将数值标签放在右侧 基础时间线柱状图创建时间线自动播放时间线设置主题…

基于FPGA的VGG16卷积神经网络加速器--WL

VGG16是一个典型的卷积神经网络&#xff0c;由13层卷积层&#xff0c;5层池化层和3层全连接层组成。且卷积层的计算时间在整个计算过程中占比极大&#xff0c;通过FPGA的并行运算可以有效的加快卷积层的计算速度。 一个卷积层可以有若干个卷积核&#xff0c;以第一层为例&#…

NetSuite 工单超额完工

用户问题 在报工时&#xff0c;完工数量能否超过工单上的计划数量&#xff1f; 解决方法 在制造相关的参数中&#xff0c;有一个参数控制: ALLOW OVERAGE ON WORK ORDER TRANSACTIONS •Check On允许超出工单计划数量 •Check Off不允许超出工单计划数量 Demo 工单计划数量…

前缀和拆分

前缀和 前缀和&#xff1a;一段序列里的前n项和 给出n个数&#xff0c;在给出q次问询&#xff0c;每次问询给出L、R&#xff0c;快速求出每组数组中一段L至R区间的和 给出一段数组&#xff0c;每次问询为求出l到r区间的和 普通方法&#xff1a;L到R进行遍历&#xff0c;那么…

Python-ElasticSearch客户端的封装(聚合查询、统计查询、全量数据)

目录 ES Python客户端介绍封装代码测试代码参考 ES Python客户端介绍 官方提供了两个客户端elasticsearch、elasticsearch-dsl pip install elasticsearchpip install elasticsearch-dsl第二个是对第一个的封装&#xff0c;类似ORM操作数据库&#xff0c;可以.filter、.group…

EverEdit的一些特殊使用教学(持续更新)

项目场景&#xff1a; EverEdit的使用经常一问三不知 搜也搜不到 解决方案&#xff1a; 先去EverEdit在线帮助文档看一下(附链接) EverEdit在线帮助文档 1.快速排序 使用快捷键时:若是小键盘&#xff0c;请同时按住fn键&#xff08;在最左下角的ctrl旁&#xff09;

220. 存在重复元素 III

220. 存在重复元素 III 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;TreeSetsequenceSet.ceilingjava中的红黑树 参考代码&#xff1a; 原题链接&#xff1a; 220. 存在重复元素 III https://leetcode.cn/problems/contains-duplicate-iii/description/ 完…

ER系列路由器多网段划分设置指南

ER系列路由器多网段划分设置指南 - TP-LINK 服务支持 TP-LINK ER系列路由器支持划分多网段&#xff0c;可以针对不同的LAN接口划分网段&#xff0c;即每一个或多个LAN接口对应一个网段&#xff1b;也可以通过一个LAN接口与支持划分802.1Q VLAN的交换机进行对接&#xff0c;实现…

幅度调制与角度调制

文章目录 前言一、调制简介1、调制定义2、调制目的3、调制的分类 二、幅度调制&#xff08;线性调制&#xff09;1、幅度调制的一般模型2、常规双边带调幅 AM①、AM 信号的产生②、AM 调制器的模型③、AM 波形和频谱④、AM 信号的特点⑤、AM 包络检波⑥、调幅系数 3、抑制载波双…

Kotlin~Facade

概念 又称门面模式&#xff0c;为复杂系统提供简单交互接口。 角色介绍 Facade&#xff1a;外观类&#xff0c;供客户端调用&#xff0c;将请求委派给响应的子系统。SubSystem&#xff1a;子系统&#xff0c;独立的子设备或子类 UML 代码实现 class Light(val name: Strin…

Oracle 19c 报ORA-704 ORA-01555故障处理---惜分飞

异常断电导致数据库无法启动,尝试对数据文件进行recover操作,报ORA-00283 ORA-00742 ORA-00312错误,由于redo写丢失无法正常应用 D:\check_db>sqlplus / as sysdba SQL*Plus: Release 19.0.0.0.0 - Production on 星期日 7月 30 07:49:19 2023 Version 19.3.0.0.0 Copyrig…

msvcp120.dll丢失的解决方法?哪种解决方法比较推荐?

msvcp120.dll是Microsoft Visual C Redistributable软件包的一部分。它是用于支持运行使用Microsoft Visual C编写的应用程序的动态链接库文件。msvcp120.dll提供了许多C标准库函数和组件&#xff0c;包括输入/输出、字符串处理、数学运算、内存管理等功能。 当您运行某个依赖于…

C++初阶——缺省参数以及函数重载

1. 缺省参数 缺省参数的分类&#xff1a;全缺省&#xff0c;半缺省 缺省参数是声明或定义函数时为函数的参数指定一个缺省值 在调用该函数时&#xff0c;若没有指定实参则采用该形参的缺省值否则使用指定的实参 void Func(int a 0) {cout<<a<<endl; }int main(…