c++----模板(进阶)

        也是好久没有更新了今天来将我们前面写过的模板更加升华一下。更加深一下。我们还记得我们前面讲过的模板,只是简单的运用模板而且还是参数类型模板。当然大家如果敏锐一点的话,应该就能看出这句话的问题看吧。我这里说的是参数类型模板,那么我们是不是还有无参数类型的模板啊。并且我们在前面还写过我们写的其他类型的模板。所以我们今天这篇博客就是来给大家讲讲非参数类型的模板,和模板的特化了。

非类型形参模板

       那么我们既然分了参数类型模板和非参数类型模板,那么我们第一步就是先看区别嘛。所以我们先来看看下面的区别:

类型形参即:出现在模板参数列表中,跟在 class 或者 typename 之类的参数类型名称
非类型形参,就是用一个常量作为类 ( 函数 ) 模板的一个参数,在类 ( 函数 ) 模板中可将该参数当成常
量来使用
大家看上面的非参数类型的区别,我们得知非类型模板就是将模板中的参数改为常量。然后这个参数可以当作常量使用。这个虽然也就很明确的说出来参数类型与非参数类型的区别了,但是我个人觉得如果只是看看书面解释的话,应该不是在出现两个的时候一下子就能分出来的吧,所以我们来看看两个类型模板的代码,直观的看一下:
我们这里的两张照片,第一张是我们的参数类型模板,第二张是非参数类型模板。我们看到的第一个区别就是我们的参数模板我们在最前面的template中写的都是class和typename。虽然我们的非参数类型模板中也写了的,但是我们这里为了对比,我们这里还写了一个正常的参数。我们主要看第二张图片中的非类型参数,我们这里直接写了一个常量的参数,不知道大家是否有联想到我们前面说过的默认参数啊。我们后面引用这个参数的话,我们都不需要传值了。我们可以直接使用这个参数的默认参数了。这下子大家应该就明确的分出了我们参数模板与非参数模板的区别了吧。当然我们不能直接了当的说是参数类型模板还是非参数类型模板好用。只能说应对不同的使用环境有不同的奇效吧。
然后我们需要注意一下的是:
  1. 非类型模板参数只允许使用整型家族,浮点数、类对象以及字符串是不允许作为非类型模板参数的。
  2. 非类型的模板参数在编译期就需要确认结果,因为编译器在编译阶段就需要根据传入的非类型模板参数生成对应的类或函数。

       我相信大家在很多我这种相关的博客中看到过这样的话,这也就证明这句话,并不是我个人认为重要的,那些大佬也是觉得重要的,所以大家一定要注意,别到时候被带进沟了。

模板特化

函数模板特化

        好了,当我们前面铺垫好了后,我们要来讲讲我们这篇博客中的重中之重了。模板的特化,我相信大家应该很少听到过这个名字。但是我们可以从这个名字上看到我们这个名字的特殊意义就是,特殊。与我们平常写的模板不一样。这里的特化更像是倾注与一个点发展。有点像术业有专攻那种。通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结果,需要特殊处理,比如:实现了一个专门用来进行小于比较的函数模板。

// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
return left < right;
}

          这是我们通常会写的判断小于的函数模板,然后我们一般的话是这样使用的

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;

        这样我们编译的话是没有错误的话,但是我们如果运行的话就比较结果就是错误的。Less绝对多数情况下都可以正常比较,但是在特殊场景下就得到错误的结果。上述示例中,p1指向的d1显然小于p2指向的d2对象,但是Less内部并没有比较p1p2指向的对象内容,而比较的是p1p2指针的地址,这就无法达到预期而错误。此时,就需要对模板进行特化。即:在原模板类的基础上,针对特殊类型所进行特殊化的实现方。模板特化中分为函数模板特化类模板特化

        所以这里我们就引出了我们如何特化,以及特化的分类了。有函数模板特化以及类模板特化。并且类模板中又分为全特化和偏特化(半特化)。

        然后我们这里函数模板的特化步骤:

1. 必须要先有一个基础的函数模板
2. 关键字 template 后面接一对空的尖括号 <>
3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
4. 函数形参表 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇
怪的错误。
         和上面写的一样,我们想要实现函数模板的特化的话,我们前提是要有一个模板,就是相当于先照着这前面的一个抄,然后我们写新的东西的时候template里面不能有其他的东西。然后再函数名后面写特定函数类型。最后就是我们需要确定我们特化的函数类型模板必须与特化的函数模板参数类型相同。主要是我们需要满足前面上个条件,然后最后一个是我们需要注意的地方。
当然我们只是光看这些的话是不能理解的,所以我们需要看看实例:
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{
return left < right;
}
// 对Less函数模板进行特化
template<>
bool Less<Date*>(Date* left, Date* right)
{
return *left < *right;
}

          我们这里看到我们的模板特化这个示例完全的体现出了我们上面写的三个特点先要有一个模板,然后写template<>,并且<>里面不能写其他。最后就是在函数名后面的<>里面写出函数特化的类型。注意得就是我们特化函数模板类型必须与我们的初始化模板类型保持一致。

类模板特化

         但是又有一个问题了,我们讲了函数模板特化,我们的类模板特化咧,但是我们这个特化有什么用啊。如果我们用官方一点的话讲就是函数模板特化指函数模板在模板参数为特定类型下的特定实现 模板的特化和函数类模板的重载类似,你可以依次重写这个函数或者类, 也可以只特化某个成员 (片特化),也可以特化整个类 (全特化)。我们白话就是讲我们特化相当于将一个大项目中有很多小组,但是这个小组只专注于处理一件事,这就是我们特化的意义,然后上面我们白话讲的是我们的偏特化,偏特化就是专注搞一个,那么我们的全特化就是全部的函数模板参数给特殊化了。

        虽然说我们的函数模板可以特化,但是我们下面该种实现简单明了,代码的可读性高,容易书写,因为对于一些参数类型复杂的函数模板,特化时特别给出,因此函数模板不建议特化。

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

         然后我们其实讲特化的话,更加倾向于类模板的特化。我们全特化就是全特化即是将模板参数列表中所有的参数都确定化。我们来看看下面的例子:

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 TestVector()
{
Data<int, int> d1;
Data<int, char> d2;
}

        我们看到我们类模板的全特化与函数模板的特化区别就是我们类名后没有<>直接是跟着我们的类成员的。并且我们的特化类的<>中写出来我们初始化的模板中写了两种参数类型,所以我们在特化的成员中可以写出两种参数类型。这就是全特化,将初始模板的参数成员全部都改掉。就是我们前面说的将模板参数中的参数全部确定。

        那么我们的全特化是将模板参数中的参数全部确定,那么我们的偏特化就是参数不全部确定。

//半特化 / 偏特化()半特化不是特化一半
//1、将部分模板参数列表中的一部分参数特化
template<class T1>
class Data<T1, char>
{
public:Data() { cout << "Data<T1, char>" << endl; }
};//2、偏特化并不仅仅是指特化部分参数,而是针对模板参数更进一步的条件限制所设计出来的一个特化版本
//只要T1 和 T2是指针就走这个 -- 针对指针特殊化处理
template<class T1, class T2>
class Data<T1*, T2*>
{
public:Data() { cout << "Data<T1*, T2*>" << endl; }
};template<class T1, class T2>
class Data<T1&, T2&>
{
public:Data() { cout << "Data<T1&, T2&>" << endl; }
};int main()
{Data<int, int> d1;Data<int, double> d2;//只要第二个是char都会匹配:半特化/偏特化Data<int, char> d3;Data<char, char> d4;//只要是两个指针Data<int*, int*> d5;Data<int*, char*> d6;Data<int*, string*> d7;Data<int*, void*> d8;//void不是类型,但是void*是一个类型,void*是不能解引用不能++Data<int*, int> d9;//匹配原生的指针Data<int&, char&> d10;return 0;
}

        像我上面的这个例子一样我们我们偏特化就是将将部分模板参数列表中的一部分参数特化。如果全部特化的话,就是我们前面的全特化了,但是我们不用值特化一半,这个没有明确规定,只要是有特化和未特化的那么就是偏特化了。

         我相信很多人都在想我们特化有什么用啊,那么大家看看下面的这个例子后在思考一下:

#include<vector>
#include<algorithm>
template<class T>
struct Less
{
bool operator()(const T& x, const T& y) const
{
return x < y;
}
};
int main()
{
Date d1(2022, 7, 7);
Date d2(2022, 7, 6);
Date d3(2022, 7, 8);
vector<Date> v1;
v1.push_back(d1);
v1.push_back(d2);
v1.push_back(d3);
// 可以直接排序,结果是日期升序
sort(v1.begin(), v1.end(), Less<Date>());
vector<Date*> v2;
v2.push_back(&d1);
v2.push_back(&d2);
v2.push_back(&d3);
// 可以直接排序,结果错误日期还不是升序,而v2中放的地址是升序
// 此处需要在排序过程中,让sort比较v2中存放地址指向的日期对象
// 但是走Less模板,sort在排序时实际比较的是v2中指针的地址,因此无法达到预期
sort(v2.begin(), v2.end(), Less<Date*>());
return 0;
}

          通过观察上述程序的结果发现,对于日期对象可以直接排序,并且结果是正确的。但是如果待排序元素是指针,结果就不一定正确。因为:sort最终按照Less模板中方式比较,所以只会比较指针,而不是比较指针指向空间中内容,此时可以使用类版本特化来处理上述问题,就像下面的代码一样

// 对Less类模板按照指针方式特化
template<>
struct Less<Date*>
{
bool operator()(Date* x, Date* y) const
{
return *x < *y;
}
};

        所以我们特化就是在面对一些情况的时候是很有作用的哦。

总结

      好了,上面就是我们这篇博客想与大家分享的模板进阶了,我们这篇博客其实主要讲模板参数中不一定是   参数类型模板,然后就是我们的特化,以及特化的使用。

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

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

相关文章

模仿抖音用户ID加密ID的算法MB4E,提高自己平台ID安全性

先看抖音的格式 对ID加密的格式 MB4EENgLILJPeQKhJht-rjcc6y0ECMk_RGTceg6JBAA 需求是 同一个ID 比如 413884936367560 每次获取得到的加密ID都是不同的&#xff0c;最终解密的ID都是413884936367560 注意这是一个加密后可解密原文的方式&#xff0c;不是单向加密 那么如下进行…

Java在零工市场中的应用:构建灵活高效的劳动力平台

随着数字经济的迅猛发展&#xff0c;零工经济作为一种新兴的劳动力市场模式&#xff0c;正在全球范围内迅速崛起。零工市场通过互联网平台将服务提供者与需求者进行快速匹配&#xff0c;使得个人可以临时、自由地提供服务&#xff0c;企业则能够按需雇佣劳动力&#xff0c;实现…

清理微信一些文件

C盘的微信文件实在是太难搞了&#xff0c;怎么弄怎么麻烦 一般文件保存在手机端或者自己的文件夹更多&#xff0c;要清理呀 不然卡秃噜皮了怎么办是啊不 路径如图

【JAVA入门】Day45 - 压缩流 / 解压缩流

【JAVA入门】Day45 - 压缩流 / 解压缩流 文章目录 【JAVA入门】Day45 - 压缩流 / 解压缩流一、解压缩流二、压缩流 在文件传输过程中&#xff0c;文件体积比较大&#xff0c;传输较慢&#xff0c;因此我们发明了一种方法&#xff0c;把文件里的数据压缩到一种压缩文件中&#x…

Linux与Ubuntu:内核与发行版的关系

在计算机科学的领域内&#xff0c;Linux和Ubuntu这两个术语频繁出现&#xff0c;但它们之间的确切联系往往不为大众所熟知。本文旨在深入探讨Linux内核与Ubuntu操作系统发行版之间的技术关系&#xff0c;并阐明它们各自的独特性质。 Linux内核&#xff1a;操作系统的基石 Lin…

双碳目标下DNDC模型建模方法及在土壤碳储量、温室气体排放、农田减排、土地变化、气候变化中的实践应用

查看原文>>> 双碳目标下DNDC模型建模方法及在土壤碳储量、温室气体排放、农田减排、土地变化、气候变化中的实践技术应用 目录 专题一、DNDC模型介绍 专题二&#xff1a;DNDC初步操作 专题三、遥感和GIS基础 专题四、DNDC气象数据 专题五、DNDC土地数据 专题六…

项目警告Added non-passive event listener to a scroll-blocking ‘touchstart‘ event.

使用touchstart和touchmove时项目报如下警告&#xff1a; 这个警告信息是由浏览器提供的&#xff0c;主要是为了提醒开发者关注性能问题。在移动设备上&#xff0c;touchstart事件可能会导致滚动操作的响应问题。当你在touchstart事件上添加了一个非被动的监听器&#xff08;即…

统计/nginx/access.log中每个ip的访问次数,按高到低排列

/nginx/access.log具体内容长这样&#xff1a; 第一个元素就是ip。 awk {print $1} /nginx/access.log | sort | uniq -c | sort -r首先&#xff0c;awk {print $1} /nginx/access.log 从 /nginx/access.log文件的每行中提取出第一个字段。然后&#xff0c;sort 对提取出的第…

多线程篇(其它容器- CopyOnWriteArrayList)(持续更新迭代)

一、CopyOnWriteArrayList&#xff08;一&#xff09; 1. 简介 并发包中的并发List只有CopyOnWriteArrayList。 CopyOnWriteArrayList是一个线程安全的ArrayList&#xff0c;对其进行的修改操作都是在底层的一个复制的数 组&#xff08;快照&#xff09;上进行的&#xff0…

MySQL迁移达梦报错,DMException: 第1 行附近出现错误: 无效的表或视图名[ACT_GE_PROPERTY]

达梦数据库选好模式和登录用户&#xff0c;迁移时的目标模式名要和达梦的当前登录的用户名相同&#xff0c;否则查询的时候需要“form 模式名.表名”&#xff0c;只from表名就会报表不存在的错误。

Orchestrator 与 Mysql 8.0 的兼容性

一、看图识别问题 二、Mysql 8.0 从 MySQL 8.0.22 开始,使用SHOW REPLICA STATUS代替SHOW SLAVE STATUS,该语句从该版本开始已弃用。 所以&#xff1a;Mysql 8.0.22前可以用Orchestartor

YOLOv5/v8 + 双目相机测距

yolov5/v8双目相机测距的代码&#xff0c;需要相机标定 可以训练自己的模型并检测测距&#xff0c;都是python代码 已多次实验&#xff0c;代码无报错。 非常适合做类似的双目课题&#xff01; 相机用的是汇博视捷的双目相机&#xff0c;具体型号见下图。 用的yolov5是6.1版本的…

并发控制全解析

在数据库操作中&#xff0c;并发控制 是确保数据一致性和事务隔离性的关键。然而&#xff0c;多个事务的并发操作可能导致数据不一致&#xff0c;破坏数据库的ACID特性。本文将深入探讨并发操作可能带来的问题&#xff0c;并介绍常见的并发控制技术。 1. 并发操作带来的挑战 …

代码随想录算法训练营第五十九天 | dijkstra(堆优化版)精讲

目录 dijkstra&#xff08;堆优化版&#xff09;精讲 思路 堆优化细节 方法一&#xff1a; 最小堆优化 dijkstra&#xff08;堆优化版&#xff09;精讲 题目链接&#xff1a;卡码网&#xff1a;47. 参加科学大会 文章讲解&#xff1a;代码随想录 小明是一位科学家&#x…

Git常用命令与基本操作(包括搭建git环境)

首先&#xff0c;在github注册邮箱&#xff0c;然后再Ubuntu下安装git和ssh服务&#xff08;如果实在windows下需要下载git bash&#xff0c;其余操作与Ubuntu相同&#xff09;。 Ubuntu搭建git环境 ssh-keygen -t rsa -C "注册账号的邮箱名字" 生成SSH通信用的公钥…

Snowflake 如何通过 Apache Iceberg 和 Polaris 为大数据的未来提供动力

Snowflake 的使命是让每个组织都成为数据驱动型组织。凭借围绕 Apache Iceberg 的最新创新和 Polaris 的推出,这家数据云公司使开发人员、工程师和架构师能够比以往任何时候都更快、更轻松地利用大数据获得变革性的业务见解。 将开放标准引入数据云 Snowflake 战略的核心是采…

Elasticsearch知识点整理

数据分类 非结构化数据 全文数据。不定长或无固定格式 报错xml,HTML,Word结构化数据 行数据&#xff0c;由二维表结构来逻辑表达和实现的数据 非结构化数据 对于非结构化的数据 搜索主要有两种方法 顺序扫描全文检索 顺序扫描 一般不建议这么做。例如给你一张报纸&…

WEB攻防-PHP特性缺陷对比函数CTF考点CMS审计实例

知识点&#xff1a; 1、过滤函数缺陷绕过&#xff1b; 2、CTF考点与代码审计&#xff1b; 1、赋值 不会对比类型 类型也会对比 2、MD5 在使用比较md5的时候&#xff0c;只要第一位是相等的数字&#xff0c;则会值相等 3、intval 3、 %0a代表换行 4、 6、 7、 代码审计

STM32+ESP01连接到机智云

机智云,全球领先的智能硬件软件自助开发及物联网(iot)云服务平台。机智云平台为开发者提供了自助式智能硬件开发工具与开放的云端服务。通过傻瓜化的自助工具、完善的SDK与API服务能力最大限度降低了物联网硬件开发的技术门槛&#xff0c;降低开发者的研发成本&#xff0c;提升…

SQL Server性能优化之读写分离

理论部分: 数据库读写分离&#xff1a; 主库&#xff1a;负责数据库操作增删改 20% 多个从库&#xff1a;负责数据库查询操作 80% 读写分离的四种模式 1.快照发布&#xff1a;发布服务器按照预定的时间间隔向订阅服务器发送已发布的数据快照 2.事务发布[比较主流常见]&#xf…