C++模板进阶(非类型模板参数 + 模板特化)

news/2025/2/1 19:41:02/

我们另一篇模板初阶介绍链接:http://t.csdn.cn/Ox8Dm

目录

 一、非类型模板参数

1.1 非类型模板参数概念

1.2 模板类型的静态数组 

二、模板特化

2.1 函数模板特化

2.2 类模板特化

2.2.1 类模板全特化

2.2.2 类模板半特化(偏特化)

 2.2.3模板特化应用场景


 一、非类型模板参数

1.1 非类型模板参数概念

模板参数分为类型参数和非类型参数!

类型参数就是出现在模板参数列表中,跟在class 或者typename之类的参数类型名称。

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

1.2 模板类型的静态数组 

将数组封装成类,类成员是一个数组!我们可以通过传非类型模板参数定义数组的大小!这样我们手动调控静态数组大小!

template<class T,size_t N=10>
class Array
{
public:Array(){for (size_t i = 0;i <_size;i++){_arr[i] = i+1;}}T operator[](size_t n){assert(n < _size);//只要发生越界直接报错return _arr[n];}size_t size()const{return _size;}
private:T _arr[N];size_t _size=N;
};

测试一下效果:


二、模板特化

2.1 函数模板特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板!

我们实现了一个比较模板函数,下面我们预比较不同类型的数据:

//模板函数
template<class T>
bool Less(const T& left, const T& right)
{return left < right;
}void Test2()
{//整形cout << " Less(1, 2)="<<Less(1, 2) << endl;//日期类Date d1(2023,1,8);Date d2(2023,1,9);cout << "Less(d1,d2)="<< Less(d1, d2) << endl;//日期类,但传的是地址Date* p1 = &d1;Date* p2 = &d2;cout <<"Less(p1, p2)="<< Less(p1, p2) << endl;
}

很明显我们发现同样希望比较日期类,第二个比较直接用Date类型,第三个用的是Date*,但是比较结果却相反!这与我们的期望不同!思考发现,原来第三个比较的并不是日期类,而是二者的地址,所以结果不同!这种情况下,我们理想的是比较*left与*right,但是模板函数参数限定了它的比较形式!也就是说范式的模板函数不能解决所有的比较,我们需要特例化!也就是特化函数模板!这里我们需要特化Date*比较!

函数模板的特化步骤:

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

特化Date* 代码:

template<class T>
bool Less(const T& left, const T& right)
{return left < right;
}template<>//这个模板列表不能省去!
bool Less<Date*>(Date* const& left, Date* const& right)
{return *left < *right;
}

特化后比较结果:


2.2 类模板特化

2.2.1 类模板全特化

template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};//类模板全特化,也就是模板参数都确定化
template<>
class Data<int, char>
{
public:Data() { cout << "Data<int, char>" << endl; }
private:int _d1;char _d2;
};//全特化测试
void Test3()
{Data<int, int> d1;Data<int, char> d2;
}

 

若模板参数匹配特化的类模板参数,则优先调用特化类模板!


2.2.2 类模板半特化(偏特化)

偏特化就是部分类模板参数具体化!如果类模板所传参数满足特化模板对应位置具体化参数!则优先调用特化模板!

//一般模板函数
template<class T1, class T2>
class Data
{
public:Data() { cout << "Data<T1, T2>" << endl; }
private:T1 _d1;T2 _d2;
};//偏特化,部分位置参数确定
template <class T1>
class Data<T1, int>
{
public:Data() { cout << "Data<T1, int>" << endl; }
private:T1 _d1;int _d2;
};//指针/引用偏特化
template <typename T1, typename T2>
class Data <T1*, T2*>
{
public:Data() { cout << "Data<T1*, T2*>" << endl; }
private:T1 _d1;T2 _d2;
};template <class T1,class T2>
class Data <T1&, T2&>
{
public:Data(const T1& d1, const T2& d2): _d1(d1), _d2(d2){cout << "Data<T1&, T2&>" << endl;}
private:const T1& _d1;const T2& _d2;
};//偏特化测试
void Test4()
{Data<double, int> d1; // 调用特化的int版本Data<int, double> d2; // 调用基础的模板Data<int*, int*> d3; // 调用特化的指针版本Data<int&, int&> d4(1, 2); // 调用特化的指针版本
}

 


 2.2.3模板特化应用场景

如果我们拿到的类型是日期类的地址,我们想要less比较的是*left和*right !但库中的一般模板参数只是比较left和right!也就是只比较地址!这样不能满足我们的需求,所以必须特化!

#include<vector>
#include<algorithm>//sort
#include <functional>//less
//模板特化应用场景
template<>
class less<Date*>
{
public:bool operator()(Date* left,Date* right){return *left > *right;}
};
void Test5()
{Date d1(2023, 1, 8);Date d2(2023, 1, 9);Date d3(2022, 12, 31);vector<Date*> v;v.push_back(&d1);v.push_back(&d2);v.push_back(&d3);sort(v.begin(), v.end(), less<Date*>());for (auto& e : v){cout << *e;}
}



http://www.ppmy.cn/news/11296.html

相关文章

【IoT】产品设计:称重传感器选型指南

最近做产品用到了称重传感器&#xff0c;由于之前从未接触过这方面的内容&#xff0c;根据最近的实际使用&#xff0c;做一下初步的总结。 这次选用的是单点式称重传感器&#xff0c;该类型是称重传感器的主要类型之一&#xff0c;在中小型平台规模的应用程序中非常常见。 当传…

声纹识别之说话人验证speaker verification

目录 一、speaker verification简介 二、主流方案和模型 1、Ecapa_TDNN模型 2、WavLm 三、代码实践 1、Ecapa_TDNN方案 a、模型结构 b、loss c、数据处理 d、模型训练和评估 e、说话人验证推理 2、WavLm预训练方案 a、模型结构和loss b、数据处理 c、模型训练 …

JavaWeb登录注册系统/界面(邮箱验证码,数据库连接,详细注释,可作结课作业,可用于学习,可接入其他主系统)

目录 1、前言 2、系统实机演示 3、系统分析与设计 &#xff08;1&#xff09;主要软件与工具 &#xff08;2&#xff09;系统分析 &#xff08;3&#xff09;系统规划 4、系统设计与构建 &#xff08;1&#xff09;JavaWeb创建 &#xff08;2&#xff09;JavaWeb运行 …

代码随想录训练营第五十七天

1.回文子串 题647 ①dp数组含义 判断回文子串可以用头元素和尾元素是否相等的方式&#xff0c;设dp[i] [j]为[i,j]子串是否为回文子串&#xff0c;是则为true&#xff0c;否为false。 ②递推公式 若 s[i] s[j] &#xff0c;分三种情况&#xff1a;i j&#xff0c;即只有一…

1.3 认识程序开发

文章目录1.程序开发流程1.1 软件定义期&#xff08;研究分析阶段&#xff09;1.2 软件开发期&#xff08;开发阶段&#xff09;1.3 软件上线期&#xff08;部署运行阶段&#xff09;2.认识浏览器2.1 浏览器如何实现访问网站的&#xff1f;2.2 HTTP协议2.3 URL地址的构成2.4 如何…

4.5 集成运放的种类及选择

一、集成运放的发展概述 集成运放自 20 世纪 60 年代问世以来&#xff0c;飞速发展&#xff0c;目前已经历了四代产品。 第一代产品基本沿用了分立元件放大电路的设计思想&#xff0c;采用了集成数字电路的制造工艺&#xff0c;利用了少量横向 PNP 管&#xff0c;构成以电流源…

Python一学就会系列:02 输出输入及数据类型

系列文章目录 Python一学就会系列&#xff1a;01 开发环境搭建 及 hello world 文章目录系列文章目录一、输出二、输入三、数据类型总结一、输出 用print()在括号中加上字符串&#xff0c;就可以向屏幕上输出指定的文字 print(hello, world)结果&#xff1a;hello, world 多…

【网络攻击手段之----- DDOS攻击】

网络攻击手段之 DDOS攻击前言网络的攻击手段常见的网络攻击手段什么是DDOS攻击如何实现DDOS攻击C代码模拟DDOS攻击如何使用C语言代码来模拟DDOS攻击提升攻击强度如何进一步提升攻击强度前言 本篇文章主要介绍DDOS攻击&#xff0c;以及DDOS攻击的实现方法&#xff0c;DDOS攻击是…