C++_Function包装器和bind

文章目录

  • 前言
    • 第一种
    • 第二种 仿函数
    • 第三种 lambda表达式
  • 一、Function包装器
  • 二、使用场景
  • 三、std::bind


前言

到目前为止的学习,我们知晓了三种方式来传函数。

第一种

#include<iostream>

int Plus(int i, int j)
{
	return i + j;
}

int main()
{
	int(*func)(int, int) = Plus;
	std::cout << func(4, 5) << std::endl;
}

这种方式是C语言就支持的写法,但是实在繁琐,且没有一定C语言功底不易理解。

第二种 仿函数

class Func {
public:
	Func(){} //无参构造函数

	int operator()(int i, int j)
	{
		return i + j;
	}
private:
};

int main()
{
	std::cout << Func()(1, 2) << std::endl;;
	Func f1;
	std::cout << f1(4, 5) << std::endl;;
	return 0;
}

很多容器例如map,set类就可以传仿函数进去。

第三种 lambda表达式

void Plus(int i, int j)
{
	std::cout << i + j << std::endl;
}

int main()
{
	std::thread t1([](int i, int j) {std::cout << i + j<< std::endl; },1 ,2);
	std::thread t2(Plus,1 ,2);
	t1.join();
	t2.join();
	return 0;
}

lambda的本质其实就是仿函数,但是lamda表达式有一个缺点就是不好确定类型,在一些例如map对象的定义时,模版的实例化不好确定类型。


提示:以下是本篇文章正文内容,下面案例可供参考

一、Function包装器

基于上面的三种不同的传函数方式,C++11提供Function来对函数进行一个整体的包装,将类型统一化,更加具有实用性和方便性。

需要包头文件 #include< functional >

int plus(int i, int j)
{
	return i + j ;
}

class Func {

public:
	Func(){} //无参构造函数

	int operator()(int i, int j)
	{
		return i + j;
	}
private:

};

class Plus {
public:
	static int plus(int i, int j)
	{
		return i + j;
	}

	int Add(int i, int j)
	{
		return i + j;
	}
};
int main()
{
	//函数名
	std::function<int(int, int)> f1(plus);

	//仿函数对象
	std::function<int(int, int)> f2 = Func();

	//lambda表达式
	std::function<int(int, int)> f3([](int i, int j) { return i + j; });


	//类的静态成员函数
	std::function<int(int, int)> f4(&Plus::plus);

	//类的成员函数
	//需要一个函数对象来调用
	std::function<int(Plus, int, int)> f5(&Plus::Add);

	std::cout << f1(1, 2) << std::endl;
	std::cout << f2(2, 3) << std::endl;
	std::cout << f3(3, 4) << std::endl;
	std::cout << f4(5, 6) << std::endl;
	std::cout << f5(Plus(),6, 7) << std::endl;
	return 0;
}

二、使用场景

LeetCode_逆波兰表达式求值
力扣这一题就可以很好反映function的使用,需要使用到操作函数来解题。
我们如果要使用map来映射操作符号和对应函数,就可以使用function来包装。

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        std::stack<int> st;
        std::map<string,function<int(int,int)>> func = {
            {"+",[](int left, int right){return left + right;}},
            {"-",[](int left, int right){return left - right;}},
            {"*",[](int left, int right){return left * right;}},
            {"/",[](int left, int right){return left / right;}}     };

        for(auto str: tokens)
        {
            if(func.find(str) != func.end())
            {
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                st.push(func[str](left,right));
            }
            else
            {
                st.push(std::stoi(str));
            }
        }

        return st.top();
    }
};

三、std::bind

bind也可以理解为一个函数包装器,接受一个可调用对象(callable object),生成一个新的可调用对象来“适应”原对象的参数列表。

int minus(int i, int j)
{
	return i - j;
}

int main()
{
	//生成的新func1与plus一致
	auto func1 = std::bind(minus, std::placeholders::_1, std::placeholders::_2);
	std::cout << "func1: " << func1(5, 1) << "   plus: " << minus(5, 1) << std::endl;

	//生成的新func2参数调换
	auto func2 = std::bind(minus, std::placeholders::_2, std::placeholders::_1);
	std::cout << "func2: " << func2(5, 1) << "   plus: " << minus(5, 1) << std::endl;

	//生成的新func3,func4,func5参数数量改变
	auto func3 = std::bind(minus, 5, std::placeholders::_1);
	std::cout << "func2: " << func3(1) << "   plus: " << minus(5, 1) << std::endl;

	auto func4 = std::bind(minus, std::placeholders::_1, 1);
	std::cout << "func2: " << func4(5) << "   plus: " << minus(5, 1) << std::endl;

	auto func5 = std::bind(minus, 5, 1);
	std::cout << "func2: " << func5() << "   plus: " << minus(5, 1) << std::endl;

	return 0;
}

在这里插入图片描述
std::placeholders::_n 在这里作为“占位符”,代表newCallable的参数,它们占据了传递给newCallable的参数的“位置”,数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。

从上面的例子中,我们可以看出bind不仅可以使新生成的可调用对象的参数顺序变化,还可以固定某个参数的值和改变参数个数。 但是看上去并不实用? 那么在哪里实用呢?

例如再上面我们讲的

	//类的成员函数
	//需要一个对象来调用
	std::function<int(Plus, int, int)> f5(&Plus::Add);

这里使用function对类的成员函数进行包装,需要传一个对象才可以,与其它的函数包装还不一样,通过bind我们就可以这样传。

class Plus {
public:
	int Add(int i, int j)
	{
		return i + j;
	}
};

int main()
{
	auto func1 = std::bind(&Plus::Add, Plus(), std::placeholders::_1, std::placeholders::_2);
	std::cout << "func1: " << func1(1, 2) << "    Plus::Add: " << Plus().Add(1, 2) << std::endl;


	std::function<int(Plus, int, int)> f5(&Plus::Add);
	std::function<int(int, int)> func2 = std::bind(f5, Plus(), std::placeholders::_1, std::placeholders::_2);
	std::cout << "func2: " << func2(1, 2) << "    f5: " << f5(Plus(), 1, 2) << std::endl;


	return 0;
}

在这里插入图片描述
这种场景下,我们就可以使用bind来创建一个新的可调用对象来少传一个临时对象。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从大厂裸辞半年,我靠它成功赚到了第一桶金,如果你失业了,建议这样做,不然时间太久了就完了

程序员接私活和创业是许多技术从业者关注的话题。下面我将介绍一些程序员接私活和创业的渠道和建议&#xff1a; 接私活的渠道&#xff1a; 自媒体平台&#xff1a; 可以利用社交媒体、个人博客、技术社区等平台展示自己的作品和技能&#xff0c;吸引潜在客户。自由工作平台&…

竞赛课第五周(并查集+Treap树的应用)

目的&#xff1a; &#xff08;1&#xff09;熟悉并掌握并查集的应用 &#xff08;2&#xff09;熟悉并掌握BST &#xff08;3&#xff09;熟悉并掌握Treap树的建立与应用 实验内容&#xff1a; 1.并查集 poj 1611 嫌疑人 严重急性呼吸系统综合症 (SARS) 是一种病因不明的…

书生·浦语大模型-第一节课笔记

视频总结 23年发布的模型在一些材料中归位指令微调模型&#xff0c;后面逐渐升级应该已经是train的模型了 技术报告总结 InternLM2 Technical Report 评测与特点 6 dimensions and 30 benchmarks, long-context modeling, and open-ended subjective evaluations长文本…

智能革命:ChatGPT3.5与GPT4.0的融合,携手DALL·E 3和Midjourney开启艺术新纪元

迷图网(kk.zlrxjh.top)是一个融合了顶尖人工智能技术的多功能助手&#xff0c;集成了ChatGPT3.5、GPT4.0、DALLE 3和Midjourney等多种智能系统&#xff0c;为用户提供了丰富的体验。以下是对这些技术的概述&#xff1a; ChatGPT3.5是由OpenAI开发的一个自然语言处理模型&#x…

设计模式学习笔记 - 设计模式与范式 -行为型:2.观察者模式(下):实现一个异步非阻塞的EventBus框架

概述 《1.观察者模式&#xff08;上&#xff09;》我们学习了观察者模式的原理、实现、应用场景&#xff0c;重点节介绍了不同应用场景下&#xff0c;几种不同的实现方式&#xff0c;包括&#xff1a;同步阻塞、异步非阻塞、进程内、进程间的实现方式。 同步阻塞最经典的实现…

springboot配置文件application.properties,application.yml/application.yaml

application.properties Springboot提供的一种属性配置方式&#xff1a;application.properties 初始时配置文件中只有一行语句。 启动时&#xff0c;比如tomcat的端口号默认8080&#xff0c;路径默认。如果我们要改变端口号及路径之类的可以在application.properties中配置。…

基于微信小程序的自习室预约系统的设计与实现

基于微信小程序的自习室预约系统的设计与实现 文章目录 基于微信小程序的自习室预约系统的设计与实现1、前言介绍2、功能设计3、功能实现4、开发技术简介5、系统物理架构6、系统流程图7、库表设计8、关键代码9、源码获取10、 &#x1f389;写在最后 1、前言介绍 伴随着信息技术…

ESP8266 WiFi物联网智能插座—上位机软件实现

1、软件架构 上位机主要作为下位机数据上传服务端以及节点调试的控制端&#xff0c;可以等效认为是专属版本调试工具。针对智能插座协议&#xff0c;对于下位机进行可视化监测和管理。 软件技术架构如下&#xff0c;主要为针对 Windows 的PC 端应用程序&#xff0c;采用WPF以及…

pyqt 创建右键菜单栏

class MainModule(QMainWindow, Ui_MainWindow):def __init__(self):super().__init__(parentNone)self.setupUi(self)# 允许出现菜单栏self.tableWidget.setContextMenuPolicy(Qt.CustomContextMenu)# 对空间添加右键菜单栏处理 self.tableWidget.customContextMenuRequested.…

C练习题(1)

变种水仙花&#xff08;来自牛课网&#xff09; 题目 变种水仙花数 - Lily Number&#xff1a;把任意的数字&#xff0c;从中间拆分成两个数字&#xff0c;比如1461 可以拆分成&#xff08;1和461&#xff09;,&#xff08;14和61&#xff09;,&#xff08;146和1),如果所有拆…

【Web】NSSCTF Round#20 Basic 两道0解题的赛后谈

目录 前言 baby-Codeigniter 组合拳&#xff01; 前言 本想着说看看go的gin框架就睡了的&#xff0c;r3师傅提醒说赛题环境已经上了&#xff0c;那不赶紧研究下&#x1f600; 主要来谈谈做题的心路历程 baby-Codeigniter 拿到题目的第一反应应该是&#xff1a;“什么是C…

[ESP32]:基于esp-modbus实现serial主机

[ESP32]&#xff1a;基于esp-modbus实现serial主机 开发环境 esp idf 5.1esp-modbus 1.0.13 使用如下指令添加组件&#xff0c;或者访问esp-modbus idf.py add-dependency "espressif/esp-modbus^1.0.13"Device parameters 对于master而言&#xff0c;需要理解的…

五、Yocto集成QT5(基于Raspberrypi 4B)

Yocto集成QT5 本篇文章为基于raspberrypi 4B单板的yocto实战系列的第五篇文章&#xff1a; 一、yocto 编译raspberrypi 4B并启动 二、yocto 集成ros2(基于raspberrypi 4B) 三、Yocto创建自定义的layer和image 四、Yocto创建静态IP和VLAN 本章节实操代码请查看github仓库&…

CVAE——生成0-9数字图像(Pytorch+mnist)

1、简介 CVAE&#xff08;Conditional Variational Autoencoder&#xff0c;条件变分自编码器&#xff09;是一种变分自编码器&#xff08;VAE&#xff09;的变体&#xff0c;用于生成有条件的数据。在传统的变分自编码器中&#xff0c;生成的数据是完全由潜在变量决定的&…

GridLayoutManager 中的一些坑

前言 如果GridLayoutManager使用item的布局都是wrap_cotent 那么会在布局更改时会出现一些出人意料的情况。&#xff08;本文完全不具备可读性和说教性&#xff0c;仅为博主方便查找问题&#xff09; 布局item: <!--layout_item.xml--> <?xml version"1.0&qu…

论文阅读: Visual Attention Network

Motivation 自注意力机制在2D自然图像领域面临3个挑战&#xff1a; 视二维图像为一维序列。对于高分辨率图像&#xff0c;二次复杂度消耗太大。只捕捉空间适应性&#xff0c;忽略通道适应性。 Contribution 设计了 Large Kernel attention(LKA)&#xff0c;包含卷积和自注意…

SpringBoot整合knife4J 3.0.3

Knife4j的前身是swagger-bootstrap-ui,前身swagger-bootstrap-ui是一个纯swagger-ui的ui皮肤项目。项目正式更名为knife4j,取名knife4j是希望她能像一把匕首一样小巧,轻量,并且功能强悍,更名也是希望把她做成一个为Swagger接口文档服务的通用性解决方案,不仅仅只是专注于前端Ui…

受益于边缘计算的三个关键应用

边缘计算和 5G 网络正在改变物联网&#xff0c;增强跨多个领域的广泛应用的功能&#xff0c;并催生大量新兴应用。我们通过研究三个突出的用例来说明边缘计算的强大功能。 工业4.0智能工厂 工业 4.0 为制造商提供了基于灵活的工业环境提高生产力和盈利能力的愿景&#xff0c;…

5.vector容器的使用

文章目录 vector容器1.构造函数代码工程运行结果 2.赋值代码工程运行结果 3.容量和大小代码工程运行结果 4.插入和删除代码工程运行结果 5.数据存取工程代码运行结果 6.互换容器代码工程运行结果 7.预留空间代码工程运行结果 vector容器 1.构造函数 /*1.默认构造-无参构造*/ …

STM32 can通信部分函数注释

相关截图: CAN模式初始化函数:u8 CAN1_Mode_Init(u8 tsjw,u8 tbs2,u8 tbs1,u16 brp,u8 mode) //CAN初始化 //tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq //tbs2:时间段2的时间单元. 范围:CAN_BS2_1tq~CAN_BS2_8tq; //tbs1:时间段1的时间单元. 范围:CAN_BS…