[C++] C++11详解 (五)function包装器、bind绑定

news2024/11/13 14:31:35

标题:[C++] C++11详解 (五)function包装器、bind

@水墨不写bug



目录

一、function包装器

二、bind绑定


正文开始:

一、function包装器

        function包装器,function实现在<functional>头文件中。C++中的function本质上是一个类模板。

        function包装器可以包装函数指针,仿函数,lambda表达式, 在一定程度上可以起到简化代码逻辑和实现的作用。

//function包装lambda表达式

int x = 10, y = 11;

function<int(int, int)> f1 = [](int a, int b)->int {return a + b; };

cout << f1(x, y) << endl;

//输出21
//function包装函数指针
int add(int a,int b)
{
	return a + b;
}
int main()
{
	function<int(int, int)> f2 = add;

	cout << f2(12, 24) << endl;
	return 0;
}
//输出36
//function包装仿函数
struct ADD
{
	int operator()(int a,int b)
	{
		return a + b;
	}
};
int main()
{
	function<int(int, int)> f3 = ADD();

	cout << f3(1, 19) << endl;
	return 0;
}
//输出20

function语法:

std::function在头文件<functional>

// 类模板原型如下
template <class T> function; // undefined

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

模板参数说明:
Ret: 被调用函数的返回类型
Args…:被调用函数的形参

        之前我们已经讲解过可变参数模板, 知道了Args代表任意类型,任意个数的参数。在具体使用时,需要为function传递模板参数,格式:

function<返回值类型(形参列表)>

        有了包装器,我们就可以讲返回值和形参列表相同的函数指针,仿函数,lambda表达式看作是同一种类型了。

        比如:初始化一个map<string,function<int(int,int)>>:(函数指针,仿函数,lambda由于被function包装过,所以可以识别为同类型)

#include<functional>
#include<iostream>
#include<map>
using namespace std;

int add(int a,int b)
{
	return a + b;
}
struct ADD
{
	int operator()(int a,int b)
	{
		return a + b;
	}
};
int main()
{
	map<string, function<int(int, int)>> opmap = 
	{ 
		{"函数指针",add},
		{"仿函数",ADD()},
		{"lambda",[](int a, int b)->int {return a + b; }} 
	};
    //函数指针,仿函数,lambda由于被function包装过,所以可以识别为同类型

	return 0;
}

        这样一来,我们只需要使用map的string来使用对应的功能即可,不需要知道内部的具体是什么实现的:

int main()
{
	map<string, function<int(int, int)>> opmap = 
	{ 
		{"函数指针",add},
		{"仿函数",ADD()},
		{"lambda",[](int a, int b)->int {return a + b; }} 
	};//函数指针,仿函数,lambda由于被function包装过,所以可以识别为同类型

	//只要根据string的标识提示使用功能即可,不需要知道具体是 函数指针,仿函数,lambda哪一个实现的。
	cout << opmap["函数指针"](1, 18) << endl;
	cout << opmap["仿函数"](9, 28) << endl;
	cout << opmap["lambda"](1, 23) << endl;

	return 0;
}

       


如果用function包装成员函数,就需要注意一些其他的规则了:

        成员函数有静态成员函数非静态成员函数(普通成员函数),由于有类域的限制,这两种都需要用到域作用限定符。

        function包装普通成员函数时,对普通成员函数取地址需要加上“&”运算符:

struct A
{
	int mu_fuc(int a,int b)
	{
		return a + b;
	}
};
int main()
{
	function<int(int, int)> f = &A::mu_fuc;

	return 0;
}

        但是编译失败,正确的写法是:需要在参数列表前面加上一个类指针:

    function<int(A*,int, int)> f = &A::mu_fuc;

         另外的一种写法也是可以达到相同的效果:

	function<int(A, int, int)> f1 = &A::mu_fuc;

        这两种写法的区别在于调用的时候,传参不同:

第一种,调用时候需要传递对象的地址

function<int(A*,int, int)> f = &A::mu_fuc;
A a;
cout << f(&a, 1, 3) << endl;

第二种,调用的时候需要传递对象

//普通成员函数
function<int(A*,int, int)> f = &A::mu_fuc;
A a;
cout << f(&a, 1, 3) << endl;

function<int(A, int, int)> f1 = &A::mu_fuc;
cout << f1(a, 3, 5) << endl;
cout << f1(A(), 8, 9) << endl;

         已经实例化的有名对象、匿名对象都是可以的。


而对于静态成员函数,可以不加上“&”操作符,但是为了统一记忆,加上“&”比较好。

        正确写法:

	function<int(int, int)> f2 = &A::no_mu_fuc;

二、bind绑定

        std::bind函数定义在头文件中,是一个函数模板,它就像一个函数包装器(适配器)接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表

// 原型如下:
template <class Fn, class... Args>
/* unspecified */ bind (Fn&& fn, Args&&... args);

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

        可以将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。

        调用bind的一般形式:

auto newCallable = bind(callable,arg_list);

        其中,newCallable本身是一个可调用对象(比如:函数指针,仿函数,lambda),arg_list是一个逗号分隔的参数列表,对应给定的callable的参数当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。

        arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。


        其实上面的讲述比较抽象,我们可以从特殊开始理解,从具体的实例来理解bind的作用;


double Div(double a, double b)
{
	if (b == 0)
		throw "div by 0";
	else
		return a / b;
}

//bind:第一个参数位置是一个可调用对象,接下来的两个参数是
//placeholders命名空间内部的唯一标识符_1,_2,_3,...
auto Newdiv = bind(Div, placeholders::_1,placeholders::_2);
	

        在调用的时候,_1代表传给Newdiv函数参数的第一个,_2代表传给Newdiv函数参数的第二个;这样就实现了顺序调整

//_1代表Newdiv调用传参的第一个参数:10
//_2代表Newdiv调用传参的第二个参数:8
auto Newdiv = bind(Div, placeholders::_1,placeholders::_2);

	cout << Newdiv(10, 8);
//最终传递给Div(10,8)

/*--------------------------------------------------------------*/
//_1代表Newdiv调用传参的第一个参数:10
//_2代表Newdiv调用传参的第二个参数:8
auto Newdiv = bind(Div, placeholders::_2, placeholders::_1);

	cout << Newdiv(10, 8);
//最终传递给Div(8,10)

        除了顺序调整,也可以实现参数个数调整;


int func(int a, int b, int c)
{
	return a + b + c;
}
int main()
{
	auto newfunc = bind(func, 100, placeholders::_1, placeholders::_2);
	cout << newfunc(9, 4);

	return 0;
}

        在上述例子中,我们固定第一个参数为100,后面两个参数需要我们自己传递。

当然,调整参数个数和参数顺序也可以混合使用。


完~

未经作者同意禁止转载

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

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

相关文章

由浅入深学习 C 语言:Hello World【提高篇】

目录 引言 1. Hello World 程序代码 2. C 语言角度分析 Hello World 程序 2.1. 程序功能分析 2.2 指针 2.3 常量指针 2.4 指针常量 3. 反汇编角度分析 Hello World 程序 3.1 栈 3.2 函数用栈传递参数 3.3 函数调用栈 3.4 函数栈帧 3.5 相关寄存器 3.6 相关汇编指令…

离散傅里叶变换(Discrete Fourier Transform, DFT)介绍,地震波分析

介绍 离散傅里叶变换&#xff08;Discrete Fourier Transform, DFT&#xff09;是一种非常重要的信号处理工具&#xff0c;它将离散时间信号从时间域转换到频率域。DFT在信号处理、图像处理、通信系统以及许多其他工程和科学领域中得到了广泛应用。为了理解DFT&#xff0c;我们…

时序预测 | 基于DLinear+PatchTST多变量时间序列预测模型(pytorch)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 DLinearPatchTST多变量时间序列 dlinear,patchtst python代码&#xff0c;pytorch架构 适合功率预测&#xff0c;风电光伏预测&#xff0c;负荷预测&#xff0c;流量预测&#xff0c;浓度预测&#xff0c;机械领域预…

3.美食推荐系统(Java项目springboot和vue)

目录 0.系统的受众说明 1 绪论 1.1研究背景 1.2研究现状 1.3研究内容 2 系统关键技术 2.1 Springboot框架 2.2 JAVA技术 2.3 MYSQL数据库 2.4 B/S结构 3 系统分析 3.1 可行性分析 3.1.1 技术可行性 3.1.2经济可行性 3.1.3操作可行性 3.2 系统性能分析 3.3 系统功能分析 3.4系统…

【3D目标检测】MMdetection3d——nuScenes数据集训练BEVFusion

引言 MMdetection3d&#xff1a;【3D目标检测】环境搭建&#xff08;OpenPCDet、MMdetection3d&#xff09; MMdetection3d源码地址&#xff1a;https://github.com/open-mmlab/mmdetection3d/tree/main?tabreadme-ov-file IS-Fusion源码地址&#xff1a;https://github.co…

139. MySQL同步ES的四种方案

文章目录 1. 前言2. 数据同步方案2.1 同步双写2.2 异步双写2.3 基于 SQL 抽取2.4 基于 Binlog 实时同步 3. 数据迁移工具选型3.1 Canel3.2 阿里云 DTS3.3 Databus3.4 其它 4. 后记 本文介绍数据同步的 4 种方案&#xff0c;并给出常用数据迁移工具&#xff0c;目录如下&#xf…

【软件测试专栏】认识软件测试、测试与开发的区别

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;软件测试专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 认识软件测试、测试与开发的区别 关键词&#xff1a;软件测试、测…

最短路算法详解(Dijkstra 算法,Bellman-Ford 算法,Floyd-Warshall 算法)

文章目录 一、Dijkstra 算法二、Bellman-Ford 算法三、Floyd-Warshall 算法 由于文章篇幅有限&#xff0c;下面都只给出算法对应的部分代码&#xff0c;需要全部代码调试参考的请点击&#xff1a; 图的源码 最短路径问题&#xff1a;从在带权图的某一顶点出发&#xff0c;找出…

【PyCharm激活码】2024年最新pycharm专业版激活码+安装教程!

一、PyCharm激活 激活码&#xff1a; KQ8KMJ77TY-eyJsaWNlbnNlSWQiOiJLUThLTUo3N1RZIiwibGljZW5zZWVOYW1lIjoiVW5pdmVyc2l0YXMgTmVnZXJpIE1hbGFuZyIsImxpY2Vuc2VlVHlwZSI6IkNMQVNTUk9PTSIsImFzc2lnbmVlTmFtZSI6IkpldOWFqOWutuahtiDorqTlh4blupflkI0iLCJhc3NpZ25lZUVtYWlsIjoi…

ArcEngine二次开发实用函数18:使用shp矢量对栅格文件进行掩模和GP授权获取

目录 1. 权限设置 2. 添加如下引用 3. 核心代码: 首先要确定要使用的gp工具需要什么权限,这个可以在工具的帮助中查看;获取权限之后,引用名称空间,编写处理代码: 下面给出具体的实例代码: 1. 权限设置 ESRI.ArcGIS.RuntimeManager.Bind(ESRI.ArcGIS.ProductCode.Eng…

介绍一下最近很火的一款游戏黑神话悟空,以及国产游戏面临的挑战

《黑神话&#xff1a;悟空》是一款由杭州游科互动科技有限公司开发的单机动作角色扮演游戏&#xff0c;以中国古典名著《西游记》为背景。游戏在2024年8月20日上线&#xff0c;支持PC&#xff08;Steam、Epic、Wegame&#xff09;和PlayStation 5平台&#xff0c;未来还将登陆X…

OpenCV绘图函数(13)绘制多边形函数函数polylines()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 画几条多边形曲线 函数原型 void cv::polylines (InputOutputArray img,InputArrayOfArrays pts,bool isClosed,const Scalar & color…

浅谈 Android 15 新 API:确保 TextView 完整展示、不被切断~

本文为稀土掘金技术社区首发签约文章&#xff0c;30天内禁止转载&#xff0c;30天后未获授权禁止转载&#xff0c;侵权必究&#xff01; 前言 很多语言和文字拥有特殊的、复杂的写法、画法&#xff0c;一个字符可能延伸到前一个字符的区域&#xff0c;甚至后一个字符的区域。 …

力扣375.猜数字大小 II

力扣375.猜数字大小 II dp dp[i][j]是说依次以从i到j的数字作为分割点(猜的数)&#xff0c;必定赢的游戏所用钱的最小值。 枚举每一列&#xff0c;从下往上算出dp[i][j]&#xff0c;最终答案为dp[1][n] class Solution {public:int getMoneyAmount(int n) {if(n 1)retu…

巧用scss实现一个通用的媒介查询代码

巧用scss实现一个通用的媒介查询代码 效果展示 实现代码 <template><div class"page-root"><div class"header"></div><div class"content"><div class"car-item" v-for"item in 9">…

20行为型设计模式——访问者模式

一、访问者模介绍 访问者模式&#xff08;Visitor Pattern&#xff09;是一种行为型设计模式&#xff0c;用于将操作封装在访问者对象中&#xff0c;以便在不改变被访问对象的类的前提下&#xff0c;定义新的操作。它允许你在不修改现有代码的情况下&#xff0c;向对象结构中添…

类和对象以及内存管理

对象拷贝时的编译器优化 现代编译器会为了尽可能提高程序的效率&#xff0c;在不影响正确性的情况下会尽可能减少⼀些传参和传返回值的过程中可以省略的拷贝。如何优化C标准并没有严格规定&#xff0c;各个编译器会根据情况自行处理。当前主流的相对新⼀点的编译器对于连续⼀个…

电池信息 v5.29.11 高级版,智能优化充电,最多可延长50%电池寿命

Charging Master 是一款非常实用的安卓 APP&#xff0c;专注于为您的手机充电提供最佳体验。借助其智能优化功能&#xff0c;Charging Master 能够最大程度地延长电池寿命&#xff0c;最多可达 50% 的节省。此外&#xff0c;该应用还提供了一系列功能&#xff0c;助您更好地管理…

提升团队效率的9款免费办公工具评测

本文主要介绍了以下9款协同办公软件&#xff1a;1.Worktile&#xff1b;2.PingCode&#xff1b;3.石墨文档&#xff1b;4.Teambition&#xff1b;5.蓝湖&#xff1b;6.工作宝&#xff1b;7.飞书&#xff1b;8.Asana&#xff1b;9.ClickUp。 在现代职场中&#xff0c;团队协作已…

GD - GD32350R_EVAL - PWM实验和验证1

文章目录 GD - GD32350R_EVAL - PWM实验和验证1概述笔记实验设计实验环境GD32350R_EVAL 的硬件连接修改程序配置 - 只产生PWM波&#xff0c;不要CMP清除波形TIMER0时钟设置TIMER0的PWM设置参数设置main()中PWM波形的开启代码示波器测量结果如果要产生4KHZ的PWM需要设置怎样的参…