【二十一】【C++】模版特化

模版的参数

类型模板参数

类型模板参数允许在定义模板时指定一个占位符,这个占位符在模板实例化时将被具体的类型替换。这使得我们能够编写与类型无关的通用代码。例如,标准库中的 std::vector<T> 使用一个类型模板参数 T,这意味着你可以有一个 std::vector<int>std::vector[std::string](std::string) 或任何其他 std::vector<T>,其中 T 是实际的类型。

 
template<class T>
class MyContainer {//...
};

在这个例子中,T 是一个类型模板参数,用于在类内部表示一个未知的类型。

非类型模板参数

非类型模板参数允许你将值(而不是类型)作为参数传递给模板。这些参数必须是编译时常量表达式,因为模板实例化发生在编译时。非类型模板参数可以是整数、枚举、指向函数或对象的指针、引用、std::nullptr_t 或者浮点数(C++20起)。

 
template<int N>
class FixedSizeArray {int array[N]; // 使用非类型参数N定义数组大小
};

在这个例子中,N 是一个非类型模板参数,用于定义固定大小数组的大小。

模板参数列表

模板参数列表可以包含类型模板参数和非类型模板参数的任意组合,它们按照声明时的顺序进行匹配。

 
template<class T, int Size>
class MyArray {T array[Size]; // 结合使用类型模板参数和非类型模板参数
};

在这个例子中,MyArray 既有一个类型模板参数 T,也有一个非类型模板参数 Size。这允许 MyArray 在实例化时指定数组的元素类型以及数组的大小。

日期类指针比较大小,错误结果

 
/*日期类指针比较大小,错误结果*/
#if 1
#include <iostream>
using namespace std;class Date {int _year;int _month;int _day;public:Date() {}Date(int year, int month, int day): _year(year), _month(month), _day(day){}bool operator<(const Date&  right) {if (this->_year < right._year) {return true;} else if (this->_year == right._year && this->_month < right._month) {return true;} else if (this->_year == right._year && this->_month == right._month && this->_day < right._day) {return true;}return false;}bool operator==(const Date& right) {return this->_year == right._year && this->_month == right._month && this->_day == right._day;}bool operator>(const Date& right) {return !(*this < right) && !(*this == right);}};template<class T>
bool Less(T left, T right) {return left < right;}int main() {cout << Less(1, 2) << endl;Date d1(2024, 1, 1);Date d2(2024, 1, 2);cout << Less(d1, d2) << endl;Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl;}
#endif

Date

Date 类用于表示日期,包含年(_year)、月(_month)和日(_day)三个私有成员变量。类中定义了几个成员函数:

构造函数:一个默认构造函数和一个接受年、月、日为参数的构造函数。

operator<:重载 < 操作符,用于比较两个 Date 对象。比较逻辑是首先比较年份,如果年份相同,则比较月份,月份相同则比较日。这保证了日期的正确顺序比较。

operator==:重载 == 操作符,用于检查两个 Date 对象是否相等,即年、月、日都相同。

operator>:重载 操作符,基于 <== 操作符的结果来判断一个 Date 对象是否大于另一个。

Less 模板函数

Less 是一个函数模板,接受两个参数并返回它们使用 < 操作符比较的结果。这个模板函数可以用于任何定义了 < 操作符的类型。

main 函数

main 函数中,进行了三种不同的比较:

  • 比较两个整数值12,使用 Less 函数,输出结果为 1true),表示 1 小于 2

  • 创建两个 Date 对象 d1d2,分别代表 2024年1月1日2024年1月2日,使用 Less 函数比较这两个对象,输出结果为 1true),表示 d1 日期小于 d2

  • 创建两个 Date 对象的指针 p1p2,分别指向 d1d2,然后尝试使用 Less 函数比较这两个指针。这里的 Less 函数比较的是指针的值(即内存地址),而不是指针所指向的 Date 对象的值。因此,输出的结果(truefalse)依赖于这两个对象在内存中的存储位置,与日期的逻辑顺序无关。

最后一次调用 Less 函数比较两个指针时,结果可能会引起混淆,因为它没有按照预期比较 Date 对象的逻辑大小,而是比较了它们的内存地址。这通常不是我们想要的行为。

模版特化概念

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果。模板特化是 C++ 中的一个功能,它允许为模板提供特定类型的特殊实现。这在需要为某些特定类型或值集合提供优化或特殊行为时非常有用。

函数模版特化解决 日期类指针比较大小

 
/*使用模版特化解决特殊情况*/
#if 1
#include <iostream>
using namespace std;class Date {int _year;int _month;int _day;public:Date() {}Date(int year, int month, int day): _year(year), _month(month), _day(day){}bool operator<(const Date&  right) {if (this->_year < right._year) {return true;} else if (this->_year == right._year && this->_month < right._month) {return true;} else if (this->_year == right._year && this->_month == right._month && this->_day < right._day) {return true;}return false;}bool operator==(const Date& right) {return this->_year == right._year && this->_month == right._month && this->_day == right._day;}bool operator>(const Date& right) {return !(*this < right) && !(*this == right);}};template<class T>
bool Less(T left, T right) {return left < right;}template<>
bool Less<Date*>(Date* left, Date* right) {return *left < *right;}int main() {cout << Less(1, 2) << endl;Date d1(2024, 1, 1);Date d2(2024, 1, 2);cout << Less(d1, d2) << endl;Date* p1 = &d1;Date* p2 = &d2;cout << Less(p1, p2) << endl;}
#endif

 
template<>
bool Less<Date*>(Date* left, Date* right) {return *left < *right;}

Less 模板函数(特化版本):

Date*(指向 Date 类的指针)特化了 Less 模板函数。这个特化版本通过解引用指针来比较指向的 Date 对象,确保当使用指针类型调用 Less 时,能够正确比较 Date 对象的内容,而不是它们的地址。

函数模版特化步骤

实现通用模板

首先我们需要实现一个通用的函数模版。先有一个通用的函数模版版本,才可能有对于这个函数模版特殊化处理的版本。

 
template<class T>
bool Less(T left, T right) {return left < right;}

全特化

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

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

  • 函数形参表: 必须要和模板函数的基础参数类型完全相同。

 
template<>
bool Less<Date*>(Date* left, Date* right) {return *left < *right;}

注意

  • C++ 不允许函数模板的偏特化,因为函数模板可以通过重载来实现相同的效果。

  • 特化必须在通用模板的声明之后和任何使用特化模板的代码之前进行。

  • 函数模版不建议特化,因为我们可以使用函数重载代替特化。

使用特化版本

当我们调用Less(p1,p2)时,检测到p1p2属于Date*类型,那么会与特化版本相匹配,并调用对应类型的特化版本函数。

类模版特化

模板特化的类型

全特化(Full Specialization):为模板的所有参数提供具体的类型或值。这意味着你为特定的模板实例化提供了一个完全定制的实现。全特化对类模板和函数模板都适用。

偏特化(Partial Specialization):仅为模板的部分参数提供具体的类型或值。偏特化允许你针对模板的某些方面提供特殊实现,而不是全部。注意,偏特化仅适用于类模板,函数模板不支持偏特化,但可以通过重载实现类似的效果。

类模版全特化

 
/*类模版全特化*/
#if 1
#include<iostream>
using namespace std;template<class T1,class T2>
class Date{
public:Date(){cout<<"Date<T1,T2>"<<endl;}
private:T1 _d1;T2 _d2;};template<>
class Date<int,char>{
public:Date(){cout<<"Date<int,char>"<<endl;}
private:int _d1;char _d2;};int main(){Date<int,int> d1;Date<int ,char> d2;}
#endif

  • 对于 d1,它是基于通用模板类 Date 的实例化,因为它使用的类型参数(int, int)没有对应的全特化版本。因此,其构造函数输出 "Date<T1,T2>"

  • 对于 d2,它匹配了为类型参数组合 int, char 提供的全特化版本,所以其构造函数输出 "Date<int,char>"

偏特化

 
/*类模版偏特化*/
#if 1
#include <iostream>
using namespace std;template<class T1, class T2>
class Date {public:Date() {cout << "Date<T1,T2>" << endl;}private:T1 _d1;T2 _d2;};template<class T1>
class Date<T1, int> {public:Date() {cout << "Date<T,int>" << endl;}private:T1 _d1;int _d2;};template<typename T1, typename T2>
class Date<T1*, T2*> {public:Date() {cout << "Date<T1*,T2*>" << endl;}private:T1* _d1;T2* _d2;};template<typename T1, typename T2>
class Date< T1&, T2&> {public:Date(const T1&d1, const T2&d2): _d1(d1), _d2(d2) {cout << "Date<const T1&,const T2&>" << endl;}private:const T1& _d1;const T2& _d2;};int main() {Date<double, int>d1;Date<int, double>d2;Date<int*, int*>d3;Date<int&, int&>d4(3, 4);}
#endif

  • d1 触发了第一个偏特化版本 Date<T,int>

  • d2 使用了基本模板,因为它不匹配任何偏特化版本。

  • d3 触发了第二个偏特化版本 Date<T1*,T2*>,正确地处理了指针类型的参数。

  • d4 触发了第三个偏特化版本 Date<T1&,T2&>,正确地处理了引用类型的参数。

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

transformer-Attention is All You Need(一)

1. 为什么需要transformer 循环模型通常沿输入和输出序列的符号位置进行因子计算。通过在计算期间将位置与步骤对齐&#xff0c;它们根据前一步的隐藏状态和输入产生位置的隐藏状态序列。这种固有的顺序特性阻止了训练样本内的并行化&#xff0c;这在较长的序列长度上变得至关重…

透光卓越,光耦继电器的独特特点全面解析

光耦继电器作为电子控制系统中的核心元件&#xff0c;其光电隔离技术为其独特之处。通过光电隔离技术&#xff0c;光耦继电器实现了输入和输出之间的电气隔离&#xff0c;有效阻止了高电压与低电压之间的直接接触。这项技术不仅提高了系统的安全性&#xff0c;还有效减少了电气…

【图论经典题目讲解】CF786B - Legacy 一道线段树优化建图的经典题目

C F 786 B − L e g a c y \mathrm{CF786B - Legacy} CF786B−Legacy D e s c r i p t i o n \mathrm{Description} Description 给定 1 1 1 张 n n n 个点的有向图&#xff0c;初始没有边&#xff0c;接下来有 q q q 次操作&#xff0c;形式如下&#xff1a; 1 u v w 表示…

计算机网络之网络安全

文章目录 1. 网络安全概述1.1 安全威胁1.1.1 被动攻击1.1.2 主动攻击 1.2 安全服务 2. 密码学与保密性2.1 密码学相关基本概念2.2 对称密钥密码体制2.2.1 DES的加密方法2.2.2.三重DES 2.3 公钥密码体制 3. 报文完整性与鉴别3.1 报文摘要和报文鉴别码3.1.1 报文摘要和报文鉴别码…

360可视门铃双摄版恢复案例

家用的智能摄像头恢复了很多&#xff0c;但是可视门铃的恢复却是第一次&#xff0c;现代社会似乎已经全方位处于监控网络之下。360的产品很多&#xff0c;可视门铃只是其众多品牌中的一个&#xff0c;这个案例能让我们窥视到360的开发小精产品的理念。 故障存储: 64G TF卡/ex…

Unity 2D Spine 外发光实现思路

Unity 2D Spine 外发光实现思路 前言 对于3D骨骼&#xff0c;要做外发光可以之间通过向法线方向延申来实现。 但是对于2D骨骼&#xff0c;各顶点的法线没有向3D骨骼那样拥有垂直于面的特性&#xff0c;那我们如何做2D骨骼的外发光效果呢&#xff1f; 理论基础 我们要知道&a…

optee CA/TA flow

以 TEEC_InvokeCommand 为例 CA—normal world EL0 //imx-optee-client\libteec\src\tee_client_api.c TEEC_InvokeCommandioctl(session->ctx->fd, TEE_IOC_INVOKE, &buf_data)通过syscall陷入内核态driver linux driver—normal world EL1 tee_ioctl // drive…

力扣题目训练(11)

2024年2月4日力扣题目训练 2024年2月4日力扣题目训练455. 分发饼干459. 重复的子字符串463. 岛屿的周长146. LRU 缓存147. 对链表进行插入排序76. 最小覆盖子串 2024年2月4日力扣题目训练 2024年2月4日第十一天编程训练&#xff0c;今天主要是进行一些题训练&#xff0c;包括简…

VMware Workstation 17.0 虚拟机安装MS-DOS 7.1完整详细步骤图文教程

VMware Workstation 17.0 虚拟机安装MS-DOS 7.1完整详细步骤图文教程 一、配置MS-DOS虚拟机机器环境二、安装MS-DOS磁盘操作系统 一、配置MS-DOS虚拟机机器环境 1.打开VMware Workstation Pro 2.新建虚拟机 3.建议选择【典型】&#xff0c;之后点击【下一步】 关于【自定义…

分省年度数据集(1990-2021年)

一、数据介绍 数据名称&#xff1a;分省年度数据集&#xff08;1990-2021年&#xff09; 数据来源&#xff1a;国家统计局-分省年度数据 数据范围&#xff1a;1990-2021年&#xff0c;包括31个省份 指标数量 &#xff1a;2981个指标 数据整理&#xff1a;自主整理 更新时…

简单的edge浏览器插件开发记录

今天在浏览某些网页的时候&#xff0c;我想要屏蔽掉某些信息或者修改网页中的文本的颜色、背景等等。于是在浏览器的控制台中直接输入JavaScript操作dom完成了我想要的功能。但是每次在网页之间跳转该功能都会消失&#xff0c;我需要反复复制粘贴js脚本&#xff0c;无法实现自动…

【数据分享】2001~2020年青藏高原植被净初级生产力数据集

各位同学们好&#xff0c;今天和大伙儿分享的是2001~2020年青藏高原植被净初级生产力数据集。如果大家有下载处理数据等方面的问题&#xff0c;您可以私信或评论。 朱军涛. (2022). 青藏高原植被净初级生产力数据集&#xff08;2001-2020&#xff09;. 国家青藏高原数据中心. …