【C++进阶(七)】仿函数深度剖析模板进阶讲解

💓博主CSDN主页:杭电码农-NEO💓

⏩专栏分类:C++从入门到精通⏪

🚚代码仓库:NEO的学习日记🚚

🌹关注我🫵带你学习C++
  🔝🔝


在这里插入图片描述

模板进阶

  • 1. 前言
  • 2. 仿函数的概念
  • 3. 仿函数的实际用途
  • 4. 模板的非类型模板参数
  • 5. 模板的特化简单介绍
  • 6. 函数模板深度剖析
  • 7. 类模板的特化深度剖析
    • 7.1 模板的全特化
    • 7.2 模板的偏特化
  • 8. 总结以及拓展

1. 前言

C++进阶中关于STL库的初级数据
结构就已经结束了,高阶数据结构如:
二叉搜索树AVL树,红黑树,哈希
等等将在C++高阶讲解.

本章重点:

本篇文章着重讲解仿函数的概念
以及自行实现一个仿函数.模板进阶
中,着重讲解非类型模板参数,模板
的特化还有模板的分离编译


2. 仿函数的概念

仿函数的本质就是一个类,此类中
运算符重载了括号()!所以它使用起来
和函数很相似,就叫做仿函数

在标准库的优先级队列的类模板中
有这样一个缺省参数叫less:

在这里插入图片描述

这个less就是一个仿函数,它会将
优先级队列变成大堆,在算法库的
sort函数默认是升序,其实就是用的less
与less对应的仿函数是greater,greater
可以将优先级队列变成小堆,将sort变成降序

我们可以模仿实现一下less的使用场景:

class Less
{
public:bool operator()(int x,int y){return x<y;}
};
int main()
{Less functor;cout<<functor(1,2);
}

注:1小于2,会返回true,打印1


3. 仿函数的实际用途

首先是使用库中的某些函数时
仿函数能很方便的改变升降序或大小堆

升序写法:

vector<int> v{9,8,7,6};
sort(v.begin(),v.end());
sort(v.begin(),v.end(),less<int>);

降序写法:

vector<int> v{6,7,8,9};
sort(v.begin(),v.end(),greater<int>);

大堆写法:

priority_queue<int> p1;
priority_queue<int,vector<int>,less<int>> p2;

小堆写法:

priority_queue<int,vector<int>,greater<int>> p;

注:优先级队列的适配器参数在仿函数
前面,想要显示传仿函数,先要穿前面的

当然,greater的内部实现和less
只差了一个符号而已,如下:

class Greater
{
public:bool operator()(int x,int y){return x>y;}
};

4. 模板的非类型模板参数

模板参数类型解析:

模板参数分类类型形参与非类型形参
类型形参即:出现在模板参数列表中
跟在class/typename之后的参数类型
非类型形参,就是用一个常量作为
类(函数)模板的一个参数,在类(函数)
模板中可将该参数当成常量来使用

比如:

template<class T,int N = 10>
class test
{T a[N];
};test<int,50> t1;
test<double> t2;

注:N=10是缺省值,没传时默认为10

在这里插入图片描述

讲到这儿就不得不介绍STL中一个不常用的容器了

在这里插入图片描述

array是静态数组
也就是固定大小的顺序容器
使用时,要显示传参N来初始化数组

array属于C++的数组,使用array
时,不管是越界读还是越界写都能
被检测到从而报错,然而使用C语言
的数组时,越界读写不一定会报错


5. 模板的特化简单介绍

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

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

Less绝对多数情况下都可以正常比较
但是在特殊场景下就得到错误的结果

比如这里我传入指针地址过来
这里的比较就会有问题,我想比较
的是指针指向的内容,然而传入指针
的话会比较指针的地址高低,就和数据无关

此时,就需要对模板进行特化
即:在原模板类的基础上
针对特殊类型所进行特殊化的实现方式

类模板分为函数模板和类模板


6. 函数模板深度剖析

函数模板的特化步骤:

  1. 必须要先有一个基础的函数模板
  2. 关键字template后面接一对空的尖括号<>
  3. 函数名后跟一对尖括号,尖括号中指定需要特化的类型
  4. 函数形参表: 必须要和模板函数的基础参数类型完全相同,如果不同编译器可能会报一些奇怪的错误
// 函数模板 -- 参数匹配
template<class T>
bool Less(T left, T right)
{return left < right;
}
// 对Less函数模板进行特化
template<>
bool Less<int*>(int* left, int* right)
{return *left < *right;//比较指针指向的内容
}

当传参时给函数传了int类型的指针
那么就不会调用第一个函数,而是走
第二个特化的函数,特化也就是特殊处理

注:一般情况下如果函数模板遇到不能处理或者处理有误的类型
为了实现简单通常都是将该函数直接给出

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

所以实际上函数模板的特化是不常用的


7. 类模板的特化深度剖析

类模板的特化分为全特化和偏特化

7.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;
};
Data<int, int> d1;
Data<int, char> d2;

和函数模板特化一样,特化的部分
要加上template<>作为格式,上面
初始化时,<int,int>类型不会走模板特化
然而<int,char>类型会走模板特化


7.2 模板的偏特化

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

然而偏特化又有两种表现形式:

  • 部分特化
  • 对参数做进一步限制

比如对于上面例子中的模板类做部分特化:

// 将第二个参数特化为int
template <class T1>
class Data<T1, int>
{
public:Data() {cout<<"Data<T1, int>" <<endl;}
private:T1 _d1;int _d2;
};

此时,只要第二个参数是int,就会
走偏特化,第二个参数不是int就不走

对上面的类做参数进一步限制:

//两个参数偏特化为指针类型
template <typename T1, typename T2>
class Data <T1*, T2*>
{ 
public:Data() {cout<<"Data<T1*, T2*>" <<endl;}
private:T1 _d1;T2 _d2;
};
//两个参数偏特化为引用类型
template <typename T1, typename 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; };

8. 总结以及拓展

补充完仿函数和模板进阶相关知识后
接下来我们将进入继承和多态的学习
继承和多态这部分在校招中考察的很多
请耐心学习~~

对于模板分离编译的拓展:

为什么模板不能分离编译?
模板分离编译问题剖析


🔎 下期预告:C++继承 🔍

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

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

相关文章

【GO 编程语言】面向对象

指针与结构体 文章目录 指针与结构体一、OOP 思想二、继承三、方法 一、OOP 思想 Go语言不是面向对象的语言&#xff0c;这里只是通过一些方法来模拟面向对象&#xff0c;从而更好的来理解面向对象思想 面向过程的思维模式 1.面向过程的思维模式是简单的线性思维&#xff0c;…

C#学生选课及成绩查询系统

一、项目背景 学生选课及成绩查询系统是一个学校不可缺少的部分&#xff0c;传统的人工管理档案的方式存在着很多的缺点&#xff0c;如&#xff1a;效率低、保密性差等&#xff0c;所以开发一套综合教务系统管理软件很有必要&#xff0c;它应该具有传统的手工管理所无法比拟的…

visual studio禁用qt-vsaddin插件更新

visual studio里qt-vsaddin插件默认是自动更新的&#xff0c;由于qt-vsaddin插件新版本的操作方式与老版本相差较大&#xff0c;且新版本不稳定&#xff0c;容易出Bug&#xff0c;所以需要禁用其自动更新&#xff0c;步骤如下&#xff1a;     点击VS2019菜单栏上的【扩展】–…

ChatGPT启蒙之旅:弟弟妹妹的关键概念入门

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

Docker Alist 在线网盘部署

文章目录 拉取镜像创建并运行查看容器自动生成的密码在浏览器中进行访问 挂载本地磁盘 拉取镜像 docker pull xhofe/alist-aria2创建并运行 # -v /data/alist:/opt/alist/data 挂载本地目录 docker run -d --restartalways -v /data/alist:/opt/alist/data -p 5244:5244 -e P…

Linux系统常用指令篇---(一)

Linux系统常用指令篇—(一) 1.cd指令 Linux系统中&#xff0c;磁盘上的文件和目录被组成一棵目录树&#xff0c;每个节点都是目录或文件。 语法:cd 目录名 功能&#xff1a;改变工作目录。将当前工作目录改变到指定的目录下。 (简单理解为进入指定目录下) 举例: cd .. : 返…

vscode 打开后 默认terminal power shell 报错 名为“.C”的驱动器不存在。

这是 默认terminal power shell 打开报的错 Test-Path : 找不到驱动器。名为“.C”的驱动器不存在。 所在位置 C:\Users\HUAWEI\Documents\WindowsPowerShell\profile.ps1:4 字符: 5 If (Test-Path "C:\Users\HUAWEI\AppData\Local\Temp\_MEI319962\Scripts\ ... …

python二次开发CATIA:文字轮廓草图

CATIA V5 版本的草图中&#xff0c;并没有文字轮廓的创建命令。通常的做法是&#xff0c;再Drawing 文件中创建所需文本-->将 Drawing 文件另存为 dwg / dxf 格式-->打开另存的文件&#xff0c;文字已转为轮廓线条-->复制线条并粘贴到草图中。 本例中&#xff0c;基于…

Hono——一个小型,简单且超快的Edges Web框架

Hono - [炎]在日语中的意思是火焰&#x1f525; - 是一个小型&#xff0c;简单且超快的Edges Web框架。它适用于任何JavaScript运行时&#xff1a;Cloudflare Workers&#xff0c;Fastly ComputeEdge&#xff0c;Deno&#xff0c;Bun&#xff0c;Vercel&#xff0c;Netlify&…

【单片机】14-I2C通信之EEPROM

1.EEPROM概念 1.EEPROM 1.1 一些概念 &#xff08;1&#xff09;一些概念&#xff1a;ROM【只读存储器---硬盘】&#xff0c;RAM【随机访问存储器--内存】&#xff0c;PROM【可编程的ROM】&#xff0c;EPROM【可擦除ROM】&#xff0c;EEPROM【电可擦除ROM】 1.2 为什么需要EE…

接口测试入门实践

简单接口搭建(表单/REST) 五步教会你写接口 首先要安装flask包: pip install flask 从flask中导入Flask类和request对象: from flask import Flask, request从当前模块实例化出一个Flask实例:appFlask(__name__)编写一个函数来处理请求 从请求对象中获取数据:arequest.values.…

LeetCode【121. 买卖股票的最佳时机】

你才不是什么小人物&#xff0c;你在我这里&#xff0c;是所有的天气和心情。 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一…

【Leetcode】滑动窗口合集

这里写目录标题 209.长度最小的子数组题目思路代码 3. 无重复字符的最长子串&#xff08;medium&#xff09;题目思路 11. 最大连续 1 的个数 III题目思路 1658. 将 x 减到 0 的最⼩操作数题目思路代码 904. 水果成篮题目思路代码 438.找到字符串中所有字母的异位词题目思路代码…

二十八、高级IO与多路转接之select

文章目录 一、五种IO模型&#xff08;一&#xff09;阻塞IO:&#xff08;二&#xff09;非阻塞IO:&#xff08;三&#xff09;信号驱动IO:&#xff08;四&#xff09;IO多路转接:&#xff08;五&#xff09;异步IO: 二、高级IO重要概念&#xff08;一&#xff09;同步通信 vs 异…

【STL】用哈希表(桶)封装出unordered_set和unordered_map

⭐博客主页&#xff1a;️CS semi主页 ⭐欢迎关注&#xff1a;点赞收藏留言 ⭐系列专栏&#xff1a;C进阶 ⭐代码仓库&#xff1a;C进阶 家人们更新不易&#xff0c;你们的点赞和关注对我而言十分重要&#xff0c;友友们麻烦多多点赞&#xff0b;关注&#xff0c;你们的支持是我…

pytorch_神经网络构建1

文章目录 pytorch简介神经网络基础分类问题分析:逻辑回归模型逻辑回归实现多层神经网络多层网络搭建保存模型 pytorch简介 为什么神经网络要自定义数据类型torch.tensor? tensor可以放在gpu上训练,支持自动求导,方便快速训练,同时支持numpy的运算,是加强版,numpy不支持这些 为…

python二次开发CATIA:导出Excel格式BOM

BOM是英文Bill of Material的缩写&#xff0c;中文翻译为“物料清单”&#xff0c;也称为产品结构表或产品结构树。它是计算机可以识别的产品结构数据文件&#xff0c;也是ERP的主导文件。BOM使系统识别产品结构&#xff0c;也是联系与沟通企业各项业务的纽带。ERP系统中的BOM的…

多线程经典代码案例及手动实现

目录 一.线程和多线程 二. 多线程的经典的代码案例 1.单例模式 2.阻塞队列 (1)概念介绍 (2)生产者消费者模型 (3)手动实现阻塞队列 (4)代码解释及问题分析 3.定时器 (1)概念介绍 (2)思路分析 (3)手动实现定时器 (4)代码解释及问题分析 问题一:优先级 问题二 :忙等…

基于SSM的电动车上牌管理系统(有报告)。Javaee项目。

演示视频&#xff1a; 基于SSM的电动车上牌管理系统&#xff08;有报告&#xff09;。Javaee项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring SpringM…

Java基本数据类型和变量

目录 一、基本数据类型 1.1 整型 1.1.1 byte 1.1.2 short 1.1.3 int 1.1.4 long 1.2 浮点型 1.2.1 float 1.2.2 double 1.3 字符型 1.4 布尔型 二、变量 2.1 变量的概念 2.2 语法格式 2.3 整型变量 2.3.1 整型变量 2.3.2 长整型变量 2.3.3 短整型变量 2.3.…