【C++】C++11 包装器

👀樊梓慕:个人主页

 🎥个人专栏:《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》《Linux》《算法》

🌝每一个不曾起舞的日子,都是对生命的辜负


目录

前言

function包装器

function包装器概述

function包装器使用

function包装器的实际应用

bind包装器

bind包装器概述

bind包装器使用


前言

我们目前学习过的可调用对象有三种:函数指针、仿函数以及lambda表达式(实际上也是仿函数),但是这三种可调用对象却又有各自的缺点,比如函数指针类型写起来比较复杂,仿函数的类型不统一,而lambda表达式语法层上就没有类型,所以C++11引入了包装器,主要就是为了封装他们,统一类型。


欢迎大家📂收藏📂以便未来做题时可以快速找到思路,巧妙的方法可以事半功倍。 

=========================================================================

GITEE相关代码:🌟樊飞 (fanfei_c) - Gitee.com🌟

=========================================================================


function包装器

function包装器概述

包装器就是对可调用对象的再封装,C++中的function本质上就是一个 『 类模板』。

function类模板的原型如下:

template <class T> function;
template <class Ret, class... Args>
class function<Ret(Args...)>;

其中Ret是被包装的可调用对象的返回类型,而Args则是被包装的可调用对象的形参类型。

function引入的目的就是为了统一三种可调用对象的类型。

那么我们如何进行包装呢?

function包装器使用

//普通函数
int f(int a, int b)
{return a + b;
}//仿函数对象
struct Functor
{
public://仿函数int operator()(int a, int b){return a + b;}
};
class Plus
{
public://类的静态成员函数static int plusi(int a, int b){return a + b;}//类的非静态成员函数double plusd(double a, double b){return a + b;}
};
int main()
{//1、包装函数指针(函数名)function<int(int, int)> func1 = f;cout << func1(1, 2) << endl;//2、包装仿函数(函数对象)function<int(int, int)> func2 = Functor();cout << func2(1, 2) << endl;//3、包装lambda表达式function<int(int, int)> func3 = [](int a, int b){return a + b; };cout << func3(1, 2) << endl;//4、类的静态成员函数//function<int(int, int)> func4 = Plus::plusi;function<int(int, int)> func4 = &Plus::plusi; //&可省略cout << func4(1, 2) << endl;//5、类的非静态成员函数function<double(Plus, double, double)> func5 = &Plus::plusd; //&不可省略cout << func5(Plus(), 1.1, 2.2) << endl;return 0;
}

注意:

  • 包装时按照function包装器的原型套就行,返回值类型与参数类型按照定义依次替换即可;
  • 取静态成员函数的地址可以不用取地址运算符“&”,但取非静态成员函数的地址必须使用取地址运算符“&”。

另外,因为类的非静态成员函数实际上还有一个隐藏的参数*this,所以再最后书写参数类型时,要将类的类型写在前面,并且传入匿名对象即可。


function包装器的实际应用

150. 逆波兰表达式求值 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/evaluate-reverse-polish-notation/description/

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+''-''*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

解题思路:

  • 定义一个栈,依次遍历所给字符串。
  • 如果遍历到的字符串是数字则直接入栈。
  • 如果遍历到的字符串是加减乘除运算符,则从栈定抛出两个数字进行对应的运算,并将运算后得到的结果压入栈中。
  • 所给字符串遍历完毕后,栈顶的数字就是逆波兰表达式的计算结果。

当时,我们是这样写的:

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> s;int sum=0;for(int i=0;i<tokens.size();i++){if(!(tokens[i]=="+" || tokens[i]=="-" || tokens[i]=="*" || tokens[i]=="/")){s.push(atoi(tokens[i].c_str()));}else{int right=s.top();s.pop();int left=s.top();s.pop();switch(tokens[i][0]){case '+':s.push(left+right);break;  case '-':s.push(left-right);break;  case '*':s.push(left*right);break;case '/':s.push(left/right);break;}}}return s.top();}
};

 那现在我们学习了很多C++的新容器新内容,我们可以写出一份更加漂亮的代码出来。

我们可以利用map容器和function包装器对以上代码做优化。

map容器存储的是键值对,那么我们就可以将操作符字符串作为键,将具体要执行的操作作为值,那这样我们利用map的[]操作符就可以得到当前要进行什么操作了。

我们可以采用很多种方式将可调用对象赋给map的值,这里我们使用lambda表达式,你当然也可以使用函数指针、仿函数等,但明显这里使用lambda表达式更加方便。

但是lambda表达式没有类型,所以我们就可以使用包装器将lambda表达式包装成function包装器,统一了类型。

class Solution {
public:int evalRPN(vector<string>& tokens) {stack<int> st;unordered_map<string, function<int(int, int)>> opMap = {{ "+", [](int a, int b){return a + b; } },{ "-", [](int a, int b){return a - b; } },{ "*", [](int a, int b){return a * b; } },{ "/", [](int a, int b){return a / b; } }};for (const auto& str : tokens){int left, right;if (str == "+" || str == "-" || str == "*" || str == "/"){right = st.top();st.pop();left = st.top();st.pop();st.push(opMap[str](left, right));}else{st.push(stoi(str));}}return st.top();}
};

从这里,我们就可以看出来包装器function的意义:

  • 将可调用对象的类型进行统一,便于我们对其进行管理。
  • 包装后明确了可调用对象的返回值和形参类型,更加方便使用者使用。

bind包装器

bind包装器概述

bind包装器有以下两种作用:

  • 调整参数的顺序(价值不大);
  • 调整参数的个数;

bind函数模板的原型如下:

template <class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);
template <class Ret, class Fn, class... Args>
/* unspecified */ bind(Fn&& fn, Args&&... args);

 其中fn是可调用对象,args...是要绑定的参数列表。


bind包装器使用

调用bind的一般形式为:auto newCallable = bind(callable, arg_list);

其中:

  • newCallable 为 新的可调用对象;
  • callable 为 被包装的可调用对象;
  • arg_list 为 被绑定的参数列表,一般为固定写法,比如placeholders::_1代表第一个参数,placeholders::_2代表第二个参数。

那我们上面说的调整参数的顺序就可以通过修改这个参数列表中的数据来实现了。

比如:

int Sub(int a, int b)
{return a - b;
}
int main()
{//调整参数顺序auto f1 = bind(Sub, placeholders::_2, placeholders::_1);cout << f1(x, y) << endl;return 0;
}

因为『 placeholders::_1』代表的就是第一个参数的位置,所以他与『 placeholders::_2』位置进行交换,就意味着封装后的f1对象,参数位置发生了改变。

那调整参数个数呢?

比如,由于非静态成员函数参数有一个隐藏的this指针,那么我们不想每次都要把它传进去,我们就可以利用bind包装一个新的函数对象出来:

class Plus
{
public:static int plusi(int a, int b){return a + b;}double plusd(double a, double b){return a - b;}
};
int main()
{//调整参数顺序//某些参数绑死function<double(double, double)> fc4 = bind(&Plus::plusd,Plus(),placeholders::_1,placeholders::_2);cout << fc4(2, 3) << endl;//这样我们使用fc4时就传递两个参数就可以了,就不需要再每次将隐藏的this也传递了function<double(double)> fc5 = bind(&Plus::plusd,Plus(),placeholders::_1,20);cout << fc5(2) << endl;//fc5绑死了两个参数return 0;
}

以上这种绑死某个参数的做法可以用于比如这个参数很固定是某个值,我们就可以采用这种方法。

那么bind包装器的意义我们总结如下:

  • 当一个函数的某些参数为固定的值时,我们可以使用bind包装器绑死某个参数。
  • bind包装器可以对函数参数的顺序进行灵活调整。

=========================================================================

如果你对该系列文章有兴趣的话,欢迎持续关注博主动态,博主会持续输出优质内容

🍎博主很需要大家的支持,你的支持是我创作的不竭动力🍎

🌟~ 点赞收藏+关注 ~🌟

=========================================================================

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

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

相关文章

RHCE:网络服务综合项目

基础配置&#xff1a; 1.配置主机名&#xff0c;静态IP地址 2.开启防火墙并配置 3.部分开启SElinux并配置 4.服务器之间使用同ntp.aliyun.com进行时间同步 5.服务器之间实现SSH免密登录 业务需求&#xff1a; 1.Server-NFS-DNS主机配置NFS服务器&#xff0c;将博客网…

【Lattice FPGA 开发】Modelsim与Diamond联合仿真

本文讲解Modelsim与Diamond进行联合仿真步骤&#xff0c;以及对遇到问题的解决与说明。 文章目录 软件版本0. Diamond设置文件为仿真文件特别注意 1. Diamond设置仿真软件为Modelsim2. Modelsim编译Lattice的库文件2.1 新建文件夹存放库文件2.2 Modelsim中建立新的仿真库2.2.1…

千锤百炼之算法Scanner和System.out引起超时解决办法

题外话 觉得这个内容还是很关键的,过来写一下吧 本次内容有点抽象大家试着听一下 正题 做过算法题的人都知道,无论是在力扣还是牛客或者别的网站刷题,很多情况下都会遇到输入输出的情况,当我们用Scanner和System.out.print()就有可能产生超时问题 如下图 接下来会有一段代…

远程计算机或设备将不接受连接_解决方法

重启了下电脑遇到了无法联网的问题&#xff0c;解决方法如下&#xff1a; 打开“控制面板”&#xff1b; 打开Internet选项&#xff1b; 点击“连接”&#xff1b; 点击“局域网设置”&#xff1b; 设置选项为下图&#xff1a; 连接成功了&#xff1a; 原因&#xff1a; 打…

数字化到底具有何种魔力!成为跟上时代的必经之路?

数字化确实具有深远的魔力和吸引力&#xff0c;成为现代企业在跟上时代步伐、实现持续发展和创新的重要驱动力。相较于传统信息化&#xff0c;数字化转型能够为企业带来更为显著和全面的降本增效效应。 首先&#xff0c;数字化转型通过深度融合信息技术和管理标准化&#xff0c…

GPU版本torch使用教程

GPU版本torch使用教程 一、下载配置CUDA和CUDNN &#xff08;1&#xff09;进入cmd使用nvidia-smi.exe查看自己电脑支持的最新CUDA版本&#xff08;可以下载地低版本&#xff09;&#xff0c;如图&#xff1a; 也可以通过NVIDIA控制面板&#xff08;NVIDIA Control Panel&am…

HTML重要标签梳理学习

1、HTML文件的框架 使用VS Code编码时&#xff0c;输入!选中第一个&#xff01;就可以快速生成一个HTML文件框架。 2、标签 <hr> <!--下划线--> <br> <!--换行--> <strong>加粗</strong> &…

C++11——线程库的理解与使用

目录 前言 一、线程库的构造 1.默认构造 2.带参构造 3.拷贝构造与赋值拷贝&#xff08;不支持&#xff09; 4.移动构造 二、线程调用lambda函数 三、线程安全与锁 1.lambda中的线程与锁 2.函数指针中的线程与锁 3.trylock() 4.recursive_mutex 5.lock_gurad守卫锁…

JAVA-服务器搭建-创建web后端项目

首先打开IDEA 点击新建项目 写好名称-模板选择 Web应用程序 -语言选择 Java 构建系统选择 Maven 然后点击下一步 选择版本-选择依赖项 Web Profile 点击创建 点击当前文件-选择编辑配置 选择左上角的加号-选择Tomcat服务器-选择本地 点击配置-选择到Tomcat目录-点击确定 起个…

利用STM32 HAL库实现USART串口通信,并通过printf重定向输出“Hello World“

一、开发环境 硬件&#xff1a;正点原子探索者 V3 STM32F407 开发板 单片机&#xff1a;STM32F407ZGT6 Keil版本&#xff1a;5.32 STM32CubeMX版本&#xff1a;6.9.2 STM32Cube MCU Packges版本&#xff1a;STM32F4 V1.27.1 上一篇使用STM32F407的HAL库只需1行代码实现US…

云仓酒庄广西发布会盛启:新老经销商欢聚南宁

原标题&#xff1a;云仓酒庄广西发布会盛启&#xff1a;新老经销商欢聚南宁&#xff0c;共襄精酿啤酒盛宴在夏日的热情与激情中&#xff0c;云仓广西发布会于今日在美丽的南宁盛大开幕。来自各地的经销商们齐聚一堂&#xff0c;共同见证了这一盛况。此次发布会不仅是一次产品的…

2024年汉字小达人活动还有5个月开赛:来做18道历年选择题备考吧

现在距离2024年第11届汉字小达人比赛还有五个多月的时间&#xff0c;如何利用这段时间有条不紊地备考呢&#xff1f;我的建议是两手准备&#xff1a;①把小学1-5年级的语文课本上的知识点熟悉&#xff0c;重点是字、词、成语、古诗。阅读理解不需要。②把历年真题刷刷熟&#x…

数电期末复习(一)数制和码制

数制和码制 1.1 概述1.2 几种常用的数制1.2.1 十进制&#xff08;Decimal&#xff09;1.2.2 二进制&#xff08;Binary&#xff09;1.2.3 二-十进制之间的转换1.2.4 十六进制和八进制1.2.5 任意进制之间的转换 1.3 二进制代码1.3.1 二-十进制码(BCD Binary Coded Decimal)1.3.2…

2023年网络安全行业:机遇与挑战并存

2023年全球网络安全人才概况 根据ISC2的《2023年全球网络安全人才调查报告》&#xff0c;全球的网络安全专业人才数量达到了550万&#xff0c;同比增长了8.7%。然而&#xff0c;这一年也见证了网络安全人才短缺达到了历史新高&#xff0c;缺口数量接近400万。尤其是亚太地区&am…

ARM_day6:实现字符串数据收发函数的封装

程序代码&#xff1a; uart4.h&#xff1a; #ifndef __UART4_H__ #define __UART4_H__ #include"stm32mp1xx_gpio.h" #include"stm32mp1xx_rcc.h" #include"stm32mp1xx_uart.h" void uart4_config(); void putchar(char dat); char getchar();…

【电机参数】直流无刷电机机械转速、ud、uq、us、输出功率、相反电动势幅值、载波周期、转矩常数

【电机参数】直流无刷电机机械转速、ud、uq、us、输出功率、相反电动势幅值、载波周期、转矩常数 前言 【电机控制】直流有刷电机、无刷电机汇总——持续更新 使用工具&#xff1a; 1.示波器&#xff1a;PICO2205A 2.电桥LCR&#xff1a;VICIOR4090A 3.电流钳&#xff1a;汉泰…

接口测试相关

接口测试&#xff0c;接口 接口是数据交互的入口和出口 接口是一套规范和标准 统一设计标准 前后端相对独立 扩展型灵活 接口文档。 接口测试 接口测试环境&#xff0c;运行程序&#xff0c;自己搭建环境 接口测试插件 谷歌postman 火狐 restclient java测试工具为j…

Linux系统的磁盘管理与文件系统

目录 一、磁盘结构 1.物理结构 2.数据结构 二、MBR与磁盘分区表示 1.MBR 2.磁盘分区表示 分区的优点 分区的缺点 三、文件系统类型 1.文件系统的组成 XFS SWAP EXT4 2.磁盘管理工具 四、Linux系统添加新硬盘的步骤 一、磁盘结构 1.物理结构 所有存储的设备都在…

【面试经典 150 | 数组】最后一个单词的长度

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;遍历 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行回顾…

Android 性能优化之黑科技开道(二)

3. 其它可以黑科技优化的方向 3.1 核心线程绑定大核 3.1.1 定义 核心线程绑定大核的思路也很容易理解&#xff0c;现在的 CPU 都是多核的&#xff0c;大核的频率比小核要高不少&#xff0c;如果我们的核心线程固定运行在大核上&#xff0c;那么应用性能自然会有所提升。 核…