C++_包装器

       

目录

1、包装器的用法

2、包装器的类型 

3、包装器的作用 

4、包装成员函数

5、bind(绑定)

5.1 bind的用法         

5.2 bind减少参数个数 

结语


前言:

        C++11的包装器,总称为function包装器,而包装器又称适配器,顾名思义包装器主要是用于包装函数的,实际上是将函数指针、仿函数类、lambda函数进行了又一层的封装。 

1、包装器的用法

       包装器的具体结构如下:

使用包装器需包头文件:<functional>// 类模板原型如下
template <class Ret, class... Args>
class function<Ret(Args...)>;模板参数说明:
Ret: 被调用函数的返回类型
Args…:可变参数包,表示被调用函数的形参可以有多个

        包装器测试代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
#include<functional>
using namespace std;int f(int a, int b)
{cout << "int f(int a, int b)" << endl;return a + b;
}int main()
{function<int(int, int)> f1 = f;//包装函数fcout << f1(1, 2) << endl;//使用包装器调用函数freturn 0;
}

        运行结果:

        从结果可以看到,若要使用包装器封装函数,则包装器的返回类型和参数必须和该函数一致,示意图如下:

        并且包装器仅仅只是封装了函数f,并且生成一个包装器对象,用包装器对象去调用包装的函数时,还是会去调用函数f的本体。 

2、包装器的类型 

        函数指针,lambda函数、仿函数类这三种函数本身是不能够直接进行赋值操作的,因为他们三个各有各的类型,然而经过包装器包装后,产生的三个包装器对象是可以直接进行相互赋值操作的。

        示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
#include<functional>
using namespace std;int f(int a, int b)
{cout << "int f(int a, int b)" << endl;return a + b;
}
struct Functor
{
public:int operator() (int a, int b){cout << "int operator() (int a, int b)" << endl;return a + b;}
};int main()
{function<int(int, int)> f1 = f;function<int(int, int)> f2 = Functor();f1 = f2;//f2赋值给f1,则f1调用的是f2的函数,即Functorcout << f1(1, 2) << endl<<endl;cout << f2(1, 2) << endl;return 0;
}

        运行结果:

3、包装器的作用 

         在一些特殊的场景下,比如一个容器要接收函数指针,lambda函数、仿函数类,则该容器的类型晦涩难写,比如函数指针的类型:void(*ptr)(),写起来比较麻烦,更不用说lambda的类型了,就算取到了他们的类型,写出来的代码也属于高耦合的代码,即该容器只能接收三者之一的数据类型。

        而包装器可以实现以上的效果,并且写出来的代码属于低耦合的代码,即以上三种类型的数据都可以写进容器里,具体示例如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
#include<functional>
#include<map>
using namespace std;int f(int a, int b)
{cout << "int f(int a, int b)" << endl;return a + b;
}
struct Functor
{
public:int operator() (int a, int b){cout << "int operator() (int a, int b)" << endl;return a + b;}
};int main()
{map < string, function<int(int, int)>> m1;//参数1为string,参数2为包装器//map的[] 进行插入元素,并返回第二个参数的引用m1["函数指针"] = f;m1["仿函数类"] = Functor();m1["lambda"] = [](int x, int y)->int{cout << "[](int x, int y)->int" << endl;return x + y;};cout << m1["函数指针"](1, 2) << endl << endl;cout << m1["仿函数类"](1, 2) << endl << endl;cout << m1["lambda"](1, 2) << endl;return 0;
}

        运行结果:

4、包装成员函数

        用包装器包装成员函数时需要考虑该成员函数是否有this指针,因为普通成员函数含this指针,而静态成员函数不含this指针,若函数中含this指针,则包装器的第一个参数一定是this指针。

        示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
#include<functional>
using namespace std;class Wrapper
{
public:static int Wrapperi(int a, int b)//静态成员函数无this指针{return a + b;}int Wrapperd(int a, int b){return a + b + res;}
private:int res = 2;
};int main()
{function<int(int, int)> f1 = Wrapper::Wrapperi;//Wrapperd含this指针,因此要包装器的参数要多写一个this的类型function<int(Wrapper, int, int)> f2 = &Wrapper::Wrapperd;//此处要加取地址符cout << f1(2, 3) << endl;cout << f2(Wrapper(), 2, 3) << endl;return 0;
}

         运行结果:

        包装带this指针的另一种写法:

5、bind(绑定)

        bind的格式:

auto newTarget = bind(target,arg_list);
//target是一个函数对象,也可以是指向函数的指针
//arg_list是调整之后的参数列表
//newTarget也是一个函数对象

        bind也是一种函数适配器,他接收一个函数对象,并且对该函数的参数列表进行调整,如形参的顺序、形参的个数,最后返回一个函数对象,该对象可以调用调整之后的函数(即调用newTarget时,实际上是以arg_list为形参列表去调用target),可用包装器接收该newTarget。

5.1 bind的用法         

        测试bind的代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
#include<functional>
using namespace std;void Wrapperi(int a, int b)
{cout << a << " ";cout << b << endl;
}int main()
{Wrapperi(2, 3);//将形参顺序倒置//placeholders表示占位符,placeholders::_2表示Wrapperi的第二个参数现在成了f1的第一个参数function<void(int, int)> f1 = bind(Wrapperi, placeholders::_2, placeholders::_1);//直接传参的写法auto f2 = bind(Wrapperi,20,10);//直接把20和10当作f2的形参f1(2, 3);//同样的调用顺序,结果实参2给到的是Wrapperi的形参bf2();return 0;
}

         运行结果:

         占位符用法的具体示意图如下:

5.2 bind减少参数个数 

         bind可以减少函数对象的参数个数,比如某函数有3个参数,因此调用该函数时需要传3个实参,但是bind可以将该函数减少为2个参数后给到一个新的函数对象,并且新函数对象调用该函数时不需要传3个实参。

        示例代码如下:

#define _CRT_SECURE_NO_WARNINGS 1#include<iostream>
#include<functional>
using namespace std;class Sub
{
public:int sub(int a, int b){return a - b;}
};
int main()
{//没有调整参数的调用方式std::function<int(Sub,int, int)> func2 = &Sub::sub;cout << func2(Sub(), 6, 3) << endl;//使用bind进行参数调整后的调用方式,调用包装器对象从3个参数变成了2个Sub s;std::function<int(int, int)> func3 = std::bind(&Sub::sub,s,placeholders::_1, placeholders::_2);cout << func3(10, 8) << endl;
}

        运行结果:

        从结果可以发现,bind之所以可以减少参数是因为在bind中已经将该参数显示调用了,所以新函数对象才可以不用再次显示调用该参数。注意:并且func3(包装器)类型的形参个数要和bind减少参数之后的形参个数相匹配

结语

        以上就是关于包装器和bind的讲解,包装器的作用就是为了能够让程序员更好的显示表示函数对象的类型,而bind则是能够让一些函数对象能够相互的兼容,比如A函数对象比B函数对象的形参多一个,其余的参数都一样,为了能够让A和B的类型相等,可以使用bind让A的形参减少一个,这样他们就可以兼容了,比如下面场景:

        最后希望本文可以给你带来更多的收获,如果本文对你起到了帮助,希望可以动动小指头帮忙点赞👍+关注😎+收藏👌!如果有遗漏或者有误的地方欢迎大家在评论区补充,谢谢大家!! 

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

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

相关文章

allegro PCB设计心得笔记(二) -- ERROR(SPMHUT-144): Illegal arc specification

使用Allegro PCB Editor设计PCB&#xff0c;其中使用了中文丝印&#xff0c;设计完成后&#xff0c;进行Tools -> Database Check&#xff0c;提示如下错误&#xff1a; 对PCB文件进行反复检查&#xff0c;也没有找到具体问题&#xff0c;但是删除中文丝印封装后&#xff0c…

vue3 uniapp 项目初始化集成配置【开箱即用】

https://gitee.com/charrie/vue3-uniapp-init 技术说明 采用vue3viteuniapp技术栈&#xff0c;setup语法糖编码方式引入unocss量子化样式引擎&#xff0c;动态css不用自己写样式&#xff0c;引用class即可&#xff0c;降低代码体积全局请求入口已封装&#xff0c;使用时自己封…

宝塔面板配置网站通过ip地址+端口,页面刷新无效。nginx反向代理后端端口。添加/xxx文件然后再访问项目。

宝塔面板配置网站通过ip地址端口&#xff0c;页面刷新无效。nginx反向代理后端端口。添加/xxx文件然后再访问项目。 一般来说vue项目build打包以后 如果 直接发布服务器 并且不使用后端接口。 是不需要配置nginx的。 假设我vue部署好了。我的ip是106.66.66.66. 但是我页面里面…

PLC数据采集网关是如何应用的?-天拓四方

PLC数据采集网关通过以太网、串口等通信接口与PLC设备连接&#xff0c;实现数据的实时采集。网关内置数据处理模块&#xff0c;可以对采集到的数据进行清洗、转换和存储&#xff0c;以满足不同应用场景的需求。同时&#xff0c;PLC数据采集网关支持多种通信协议&#xff0c;如M…

1.Spring核心功能梳理

概述 本篇旨在整体的梳理一下Spring的核心功能,让我们对Spring的整体印象更加具体深刻,为接下来的Spring学习打下基础。 本片主体内容如下: Bean的生命周期依赖注入的实现Bean初始化原理推断构造方法原理AOP的实现这里要说明一下,我们这里说到的Spring,一般指的是Spring F…

基于Java (spring-boot)的房屋租赁系统

一、项目介绍 有以下模块 角色&#xff1a;用户、管理员、房东 管理员&#xff1a;个人中心、房屋类型管理、房屋信息管理、预约看房管理、合同信息管理、房屋报修管理、房屋评价管理、系统管理 用户:个人中心、房屋信息管理、预约看房管理、合同信息管理、房屋报修管理、房屋…

差分逻辑电平 --- LVDS、CML、LVPECL互连

前言 首先了解差分逻辑电平结构&#xff0c;也包括单端逻辑电平 地址&#xff1a;常见的逻辑电平_常用的逻辑电平-CSDN博客 注&#xff1a;ECL >> PECL >> LVPECL演变而来&#xff1b;QDR&#xff08;Quad Data Rate):四倍数据倍率 本文章只涉及差分逻辑电平:LVDS…

在dpvs上实现ICMP的源进源出

目录 1. 缘起2. 源码分析3. 让ICMP也走源进源出1. 缘起 在网络通信中,当一个请求报文从源主机到达目标主机,并经过中间路由器或交换机进行转发时,请求报文进入主机A的路径和响应报文离开主机A的路径可能不同。这种情况下,就会出现所谓的三角路径问题。如下图: 具体来说,…

C++第二弹---C++入门(中)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 C入门 1、函数重载 1.1、函数重载概念 1.2、C支持函数重载的原理--名字修饰(name Mangling) 3、引用 3.1、引用概念 3.2、引用特性 3.3、常引用 …

批量PDF转HTML:高效管理与优化文档格式

随着数字化时代的快速发展&#xff0c;PDF文件因其跨平台兼容性和良好的排版效果而被广泛应用。然而&#xff0c;在文本批量管理的场景中&#xff0c;我们可能需要将PDF文件转换为HTML格式&#xff0c;以便更好地进行编辑、搜索和定制。本文将为您介绍一种高效的方法&#xff0…

Java线程的基本操作

线程的基本操作 Java线程的常用操作都定义在Thread类中&#xff0c;包括一些重要的静态方法 和线程的实例方法 。下面我们来学习一下&#xff0c;线程的常用基本操作 1.线程名称的设置和获取 线程名称可以通过构造Thread的时候进行设置&#xff0c;也可以通过实例的方法setName…

NOIP2018-S-DAY1-3-赛道修建(洛谷P5021)的题解

目录 题目 原题描述&#xff1a; 题目描述 输入格式 输出格式 输入输出样例 主要思路&#xff1a; check&#xff1a; 真正的code: 原题描述&#xff1a; 题目描述 C 城将要举办一系列的赛车比赛。在比赛前&#xff0c;需要在城内修建 条赛道。 C 城一共有 个路…

rancher里的ingress如何配置gzip压缩

方案一&#xff0c;未试验成功&#xff0c;但配置过程值得记录一下 通过配置configmap&#xff0c;然后在ingress的deployment里引用configmap实现。 参考文章 创建configmap apiVersion: v1 kind: ConfigMap metadata:name: nginx-ingress-controllerannotations:{} # k…

WPF Button去除按钮边框,添加下划线

<Button Width"45" Height"25" FontSize"20" Background"Transparent" BorderBrush"Transparent" Foreground"#FFC9A322" Click"Btn_Retry_Click" ><TextBlock><Underline>重试</…

01_lombok review

文章目录 Lombok父子工程ide中的Maven基础配置前置知识储备 Lombok 怎么引入Lombok依赖&#xff1a; step1&#xff1a;引入Lombok依赖 eg&#xff1a; <dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok<…

数据库管理-第159期 Oracle Vector DB AI-10(20240311)

数据库管理159期 2024-03-11 数据库管理-第159期 Oracle Vector DB & AI-10&#xff08;20240311&#xff09;1 其他distance函数2 实例演示使用其他函数寻找最近向量点函数变体简写语法 总结 数据库管理-第159期 Oracle Vector DB & AI-10&#xff08;20240311&#x…

网络安全AI智能体公司「云起无垠」获数千万元天使+轮融资,致力于大模型与网络安全深度融合的技术研究

「云起无垠」致力于打造最懂安全的AI智能体&#xff0c;通过持续运营的工具、知识以及记忆引擎&#xff0c;不断提升智能体对用户安全场景的理解&#xff0c;以达到易于使用、自我学习、自主行动的特性&#xff0c;助力企业自动化执行各类安全任务&#xff0c;让软件更安全&…

解决:黑马webpack视频中出现的问题总结

问题 1 ERROR in main Module not found: Error: Can‘t resolve ‘./src‘ 解决 Webpack 中 ERROR in main Module not found: Error: Can‘t resolve ‘./src‘ 问题 黑马AJAX-Node.js-Webpack教学视频&#xff08;BV1MN411y7pw 其中P98&#xff09;中webpack部分&#xff0c…

代理IP如何应对自动化测试和爬虫检测

目录 一、代理IP在自动化测试和爬虫中的作用 二、代理IP的优缺点分析 1.优点 2.缺点 三、应对自动化测试和爬虫检测的策略 1.选择合适的代理IP 2.设置合理的请求频率和间隔 3.模拟人类行为模式 4.结合其他技术手段 四、案例与代码示例 五、总结 在自动化测试和爬虫开…

传递函数硬件化

已知一个系统的传递函数&#xff0c;如何进行硬件化呢&#xff1f; 只需要将传递函数离散化&#xff0c;得到差分方程&#xff0c;就可以根据差分方程进行硬件设计。 通过例子说明&#xff1a; 得到差分方程后&#xff0c;其中y(k)/y(k-1)/y(k-2)/u(k-1)/u(k-2)等代表不同周期…