C++模板进阶操作 —— 非类型模板参数、模板的特化

news2025/1/20 10:54:02

C++模板进阶

  • 非类型模板参数
  • 模板的特化
    • 概念
  • 函数模板特化
  • 类模板特化
      • 全特化
    • 偏特化
    • 模板总结

非类型模板参数

模板参数可分为类型形参和非类型形参。
类型形参: 出现在模板参数列表中,跟在class或typename关键字之后的参数类型名称。
非类型形参: 用一个常量作为类(函数)模板的一个参数,在类(函数)模板中可将该参数当成常量来使用。

例如,我们要实现一个静态数组的类,就需要用到非类型模板参数。

template<class T, size_t N> //N:非类型模板参数
class StaticArray
{
public:
	size_t arraysize()
	{
		return N;
	}
private:
	T _array[N]; //利用非类型模板参数指定静态数组的大小
};

使用非类型模板参数后,我们就可以在实例化对象的时候指定所要创建的静态数组的大小了。

int main()
{
	StaticArray<int, 10> a1; //定义一个大小为10的静态数组
	cout << a1.arraysize() << endl; //10
	StaticArray<int, 100> a2; //定义一个大小为100的静态数组
	cout << a2.arraysize() << endl; //100
	return 0;
}

注意:

非类型模板参数只允许使用整型家族,浮点数、类对象以及字符串是不允许作为非类型模板参数的。
非类型的模板参数在编译期就需要确认结果,因为编译器在编译阶段就需要根据传入的非类型模板参数生成对应的类或函数。

模板的特化

概念

这里举一个简单的例子来说明什么是特化,下面是用于比较两个任意相同类型的数据是否相等的函数模板。

template<class T>
bool IsEqual(T x, T y)
{
	return x == y;
}

我们大概会这样使用该函数模板:

cout << IsEqual(1, 1) << endl; //1
cout << IsEqual(1.1, 2.2) << endl; //0

这样使用是没有问题的,它的判断结果也是我们所预期的,但是我们也可能会这样去使用该函数模板:
判断结果是这两个字符串不相等,这很好理解,因为我们希望的是该函数能够判断两个字符串的内容是否相等,而该函数实际上判断是确实这两个字符串所存储的地址是否相同,这是两个存在于栈区的字符串,其地址显然是不同的。
类似于上述实例,使用模板可以实现一些与类型无关的代码,但对于一些特殊的类型可能会得到一些错误的结果,此时就需要对模板进行特化,即在原模板的基础上,针对特殊类型进行特殊化的实现方式

函数模板特化

对于上述实例,我们知道当传入的类型是char* 时,应该依次比较各个字符的ASCII码值进而判断两个字符串是否相等,或是直接调用strcmp函数进行字符串比较,那么此时我们就可以对char*类型进行特殊化的实现。
函数模板的特化步骤:

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

//基础的函数模板
template<class T>
bool IsEqual(T x, T y)
{
	return x == y;
}
//对于char*类型的特化
template<>
bool IsEqual<char*>(char* x, char* y)
{
	return strcmp(x, y) == 0;
}

注意: 一般情况下,如果函数模板遇到不能处理或者处理有误的类型,为了实现简单通常都是将该函数直接给出。例如,上述实例char*类型的特化还可以这样给出:

//基础的函数模板
template<class T>
bool IsEqual(T x, T y)
{
	return x == y;
}
//对于char*类型的特化
bool IsEqual(char* x, char* y)
{
	return strcmp(x, y) == 0;
}

类模板特化

不仅函数模板可以进行特化,类模板也可以针对特殊类型进行特殊化实现,并且类模板的特化又可分为全特化和偏特化(半特化)。

全特化

全特化即是将模板参数列表中所有的参数都确定化。
例如,对于以下类模板:

template<class T1, class T2>
class Dragon
{
public:
	//构造函数
	Dragon()
	{
		cout << "Dragon<T1, T2>" << endl;
	}
private:
	T1 _D1;
	T2 _D2;
};

当T1和T2分别是double和int时,我们若是想对实例化的类进行特殊化处理,那么我们就可以对T1和T2分别是double和int时的模板进行特化。

函数模板的特化步骤:
1.首先必须要有一个基础的类模板。
2.关键字template后面接一对空的尖括号<>。
3.类名后跟一对尖括号,尖括号中指定需要特化的类型。
对于T1是double,T2是int的特化如下:

//对于T1是double,T2是int时进行特化
template<>
class Dragon<double, int>
{
public:
	//构造函数
	Dragon()
	{
		cout << "Dragon<double, int>" << endl;
	}
private:
	double _D1;
	int _D2;
};

那么如何证明当T1是double,T2是int时,使用的就是我们自己特化的类模板呢?
当我们实例化一个对象时,编译器会自动调用其默认构造函数,我们若是在构造函数当中打印适当的提示信息,那么当我们实例化对象后,通过观察控制台上打印的结果,即可确定实例化该对象时调用的是不是我们自己特化的类模板了。
在这里插入图片描述

偏特化

偏特化是指任何针对模板参数进一步进行条件限制设计的特化版本。

template<class T1, class T2>
class Dragon
{
public:
	//构造函数
	Dragon()
	{
		cout << "Dragon<T1, T2>" << endl;
	}
private:
	T1 _D1;
	T2 _D2;
};

偏特化又可分为以下两种表现形式:
1、部分特化
我们可以仅对模板参数列表中的部分参数进行确定化。
例如,我们可以对T1为int类型的类进行特殊化处理。

//对T1为int的类进行特化
template<class T2>
class Dragon<int, T2>
{
public:
	//构造函数
	Dragon()
	{
		cout << "Dragon<int, T2>" << endl;
	}
private:
	int _D1;
	T2 _D2;
};

在这里插入图片描述

2、参数更进一步的限制

//两个参数偏特化为指针类型
template<class T1, class T2>
class Dragon<T1*, T2*>
{
public:
	//构造函数
	Dragon()
	{
		cout << "Dragon<T1*, T2*>" << endl;
	}
private:
	T1 _D1;
	T2 _D2;
};
//两个参数偏特化为引用类型
template<class T1, class T2>
class Dragon<T1&, T2&>
{
public:
	//构造函数
	Dragon()
	{
		cout << "Dragon<T1&, T2&>" << endl;
	}
private:
	T1 _D1;
	T2 _D2;
};

此时,当实例化对象的T1和T2同时为指针类型或同时为引用类型时,就会分别调用我们特化的两个类模板。
在这里插入图片描述

模板总结

优点:

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

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

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

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

相关文章

基于springboot智慧外贸平台源码和论文

网络的广泛应用给生活带来了十分的便利。所以把智慧外贸管理与现在网络相结合&#xff0c;利用java技术建设智慧外贸平台&#xff0c;实现智慧外贸的信息化。则对于进一步提高智慧外贸管理发展&#xff0c;丰富智慧外贸管理经验能起到不少的促进作用。 智慧外贸平台能够通过互…

第三百五十三回

文章目录 1. 概念介绍2. 使用方法2.1 获取所有时区2.2 转换时区时间 3. 示例代码4. 内容总结 我们在上一章回中介绍了"分享一些好的Flutter站点"相关的内容&#xff0c;本章回中将介绍timezone包.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

基于Robei EDA--实现串口数据包接收

一、定义串口传输协议帧 控制字的数据大小为一字节&#xff0c;定义帧头为&#xff08;0xFE 0xDF&#xff09;帧尾为&#xff08;0xEF&#xff09; 模块框图 内模块&#xff1a;串口接收&#xff0c;output&#xff1a;8位data 串口命令&#xff1a;对单字节数据接收进行缓存…

问界M7卖爆了,只因这三点做得好!

文 | AUTO芯球 作者 | 雷歌 理想真是懵了个大圈&#xff01; 2月第一周的新能源汽车销量榜单已经出来&#xff1a;理想7200台的销量&#xff0c;被华为问界9000辆的销量远远甩在身后。 要知道&#xff0c;1月第四周&#xff0c;理想还以8500辆领先问界的8300辆。 更绝的是&…

算法学习——LeetCode力扣二叉树篇4

算法学习——LeetCode力扣二叉树篇4 222. 完全二叉树的节点个数 222. 完全二叉树的节点个数 - 力扣&#xff08;LeetCode&#xff09; 描述 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xf…

深入浅出熟悉OpenAI最新大作Sora文生视频大模型

蠢蠢欲动&#xff0c;惴惴不安&#xff0c;朋友们我又来了&#xff0c;这个春节真的过的是像过山车&#xff0c;Gemini1.5 PRO还没过劲&#xff0c;OpenAI又放大招&#xff0c;人类真的要认输了吗&#xff0c;让我忍不住想要再探究竟&#xff0c;到底是什么让文生视频发生了质的…

C语言—字符数组(3)

可能不是那么的完整&#xff0c;先凑合看吧&#xff0c;如果我学会如何修改以后&#xff0c;我慢慢回来修改的 1.编写程序实现对两个字符串的连接功能&#xff1b; 法一:不使用strcat函数,写程序直接实现&#xff0c;记得添加结束符&#xff0c;不然程序访问数组时候将变得不…

算法基础——单调栈,单调队列

目录 1.单调栈 例题&#xff1a;【模板】单调栈 例题:求和 2.单调队列 例题&#xff1a;滑动窗口 1.单调栈 例题&#xff1a;【模板】单调栈 可以想象出一个柱状图&#xff0c;值越大&#xff0c;这个柱子越高 以此题的样例为例&#xff1a; 第一个数为7&#xff0c;想…

.ma1x0勒索病毒解密方法|勒索病毒解决|勒索病毒恢复|数据库修复

尊敬的读者&#xff1a; 数据安全问题备受关注。而勒索病毒是其中一种最为恶劣的威胁之一。其中&#xff0c;.ma1x0勒索病毒备受人们担忧&#xff0c;因其可将用户的数据文件加密&#xff0c;并要求支付赎金以解密文件。本文将介绍.ma1x0勒索病毒的特征、预防方法以及如何恢复…

GIS分析和摄影测量进行屋顶太阳能潜力评估

目前,不可再生的能源资源有限,而减少全球变暖的想法使可再生能源的利用成为当务之急。其中,太阳能作为最清洁、最丰富的可再生能源备受关注。此外,成本的日益降低也使太阳能成为一种极具吸引力的能源。然而,为了从太阳能中获得最大利益,必须考虑各种标准,并选择合适的区…

SG3225EAN规格书

SG3225EAN 晶体振荡器利用先进的锁相环技术和AT切割晶体单元&#xff0c;提供了宽频率范围和高性能LV-PECL输出&#xff0c;73.5 MHz至700 MHz的宽频率范围&#xff0c;能够保证高稳定性和宽频率调整的能力&#xff0c;适应于多样化的应用需求。2.5V和3.3V两种供电电压&#xf…

Spring 用法学习总结(四)之 JdbcTemplate 连接数据库

&#x1f409;目录 9 JdbcTemplate 9 JdbcTemplate Spring 框架对 JDBC 进行了封装&#xff0c;使用 JdbcTemplate 方便实现对数据库操作 相关包&#xff1a; 百度网盘链接https://pan.baidu.com/s/1Gw1l6VKc-p4gdqDyD626cg?pwd6666 创建properties配置文件 &#x1f4a5;注意…

Stackoverflow(1)-根据RequestBody的内容来区分使用哪个资源

如果使用Spring&#xff0c;可以通过RequestBody将请求体的json转换为Java对象&#xff0c;但如果URI相同&#xff0c;而请求体的内容不同&#xff0c;应该怎么办&#xff1f;问题来源(stackoverflow)&#xff1a;Spring RequestBody without using a pojo?稍微研究了一下&…

vue-router 实现路由懒加载

在现代的Web开发中&#xff0c;前端技术的发展日新月异。在构建大规模单页应用&#xff08;Single Page Application&#xff09;时&#xff0c;路由管理是一个非常重要的环节。随着用户对网页速度和性能的要求越来越高&#xff0c;有效的路由管理能够显著提升用户体验。本篇博…

torch.utils.data

整体架构 平时使用 pytorch 加载数据时大概是这样的&#xff1a; import numpy as np from torch.utils.data import Dataset, DataLoaderclass ExampleDataset(Dataset):def __init__(self):self.data [1, 2, 3, 4, 5]def __getitem__(self, idx):return self.data[idx]def…

GitKraken Create Repository and Clone不可点击

问题 GitKraken Create Repository and Clone不可点击 详细问题 笔者第一次使用GitKraken&#xff0c;在创建仓库时&#xff0c;填写完成仓库初始化后。发现Create Repository and Clone不可点击。 解决方案 选择Where to clone to位置 产生原因 在创建仓库时&#xff0…

IO 作业 24/2/18

1> 使用fgets统计给定文件的行数 #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, const char *argv[]) {//定义文件指针FILE *fpNULL;//打开文件&#xff08;只读&#xff09;if((fpfopen("./test.txt",&quo…

机器人内部传感器-位置传感器-电位器式位置传感器

位置传感器 位置感觉是机器人最基本的感觉要求&#xff0c;可以通过多种传感器来实现。位置传感器包括位置和角度检测传感器。常用的机器人位置传感器有电位器式、光电式、电感式、电容式、霍尔元件式、磁栅式及机械式位置传感器等。机器人各关节和连杆的运动定位精度要求、重…

suse15 sp3-sp5离线安装中安装FIO

没有网络的情况下&#xff0c;离线安装相对比较困难一点&#xff0c;所有需要提前下载相应的RPM安装包 FIO 安装包链接如下&#xff1a; Install package benchmark / fio 正常安装的时候&#xff0c;会出现问题 如下&#xff1a; google下 https://opensuse.pkgs.org/15.5/…

WorkPlus Meet助力企业建立安全可靠的私有化视频会议平台

企业需要保护敏感信息和保证会议质量的同时&#xff0c;提高会议的效率和协作水平。作为一款私有化视频会议软件系统&#xff0c;WorkPlus Meet以其卓越的性能和高度私密的特性&#xff0c;助力企业打造安全可靠的私有化视频会议平台。 为何选择WorkPlus Meet作为私有化视频会议…