C++之可调用对象、bind绑定器和function包装器
可调用对象
在C++中,可以像函数一样调用的有:普通函数、类的静态成员函数、仿函数、lambda函数、类的非静态成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。
可调用对象有类型,可以用指针存储它们的地址,可以被引用(类的成员函数除外)。
这里举几个例子
仿函数(本质是重载了()的类)
#include<iostream>
using namespace std;
struct Object
{void operator()(int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;}
};
int main()
{Object obj;obj(20, "小谢");Object& obj_r = obj; // 引用函数obj_r(19, "小赵");return 0;
}
lambda函数
#include<iostream>
using namespace std;
int main()
{auto func = [](int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;};func(20, "小谢");auto& func_r = func;// 引用lambda对象。func_r(19, "小赵");return 0;
}
类的非静态成员函数
类的非静态成员函数有地址,但是,只能通过类的对象才能调用它,所以,C++对它做了特别处理。
类的非静态成员函数只有指针类型,没有引用类型,不能引用。
#include<iostream>
using namespace std;
struct Object
{void show(int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;}
};
int main()
{Object obj;obj.show(20, "小谢");void(Object::*pobj)(int, string) = &Object::show;// 定义类的成员函数的指针。(obj.*pobj)(19, "小赵");using PFun = void(Object::*)(int, string);PFun p_show = &Object::show;(obj.*p_show)(18, "芜湖");return 0;
}
在上面的例子中满足条件的这些可调用对象对应的类型被统称为可调用类型。C++ 中的可调用类型虽然具有比较统一的操作形式,但定义方式五花八门,这样在我们试图使用统一的方式保存,或者传递一个可调用对象时会十分繁琐。现在,C++11通过提供std::function 和 std::bind统一了可调用对象的各种操作。
包装器function
包含头文件:#include <functional>
std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;
#include<iostream>
#include<functional>
using namespace std;
int add(int a, int b)
{cout << a << "+" << b << "=" << a + b << endl;return a + b;
}
class T
{
public:static int sub(int a, int b){cout << a << "*" << b << "=" << a * b << endl;return a * b;}
};
class T1
{
public:int operator()(int a, int b){cout << a << "-" << b << "=" << a - b << endl;return a - b;}
};
int main()
{//std::function<返回值类型(参数类型列表)> diy_name = 可调用对象;function<int(int, int)> f1 = add;f1(1, 2);function<int(int, int)> f2 = T::sub;f2(2, 3);T1 t;function<int(int, int)> f3 = t;f3(3, 4);return 0;
}
通过测试代码可以得到结论:std::function 可以将可调用对象进行包装,得到一个统一的格式,包装完成得到的对象相当于一个函数指针,和函数指针的使用方式相同,通过包装器对象就可以完成对包装的函数的调用了。
作为回调函数使用
#include <iostream>
#include <functional>
using namespace std;
class A
{
public:// 构造函数参数是一个包装器对象A(const function<void()>& f) : callback(f){}void notify(){callback(); // 调用通过构造函数得到的函数指针}
private:function<void()> callback; //成员变量->包装器对象
};class B
{
public:void operator()(){cout << "!!!" << endl;}
};
int main(void)
{B b;A a(b);a.notify();return 0;
}
绑定器bind
std::bind()模板函数是一个通用的函数适配器(绑定器),它用一个可调用对象及其参数,生成一个新的可调用对象,以适应模板。
函数原型
template< class Fx, class... Args >function<> bind (Fx&& fx, Args&...args);
Fx:需要绑定的可调用对象
args:/*绑定参数列表,可以是左值、右值和参数占位符std::placeholders::_n,如果参数不是占位符,缺省为值传递,std:: ref(参数)则为引用传递。*/
std::bind()返回std::function的对象。
std::bind()的本质是仿函数。
// 绑定非类成员函数/变量
auto f = std::bind(可调用对象地址, 绑定的参数/占位符);
// 绑定类成员函/变量
auto f = std::bind(类函数/成员地址, 类实例对象地址, 绑定的参数/占位符);
类成员函数需要绑定该类的this指针 。
#include<iostream>
#include<functional>
using namespace std;
struct Object
{void operator()(int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;}void show(int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;}};
int main()
{Object obj;function<void(int, string)> f1 = bind(Object(), placeholders::_1, placeholders::_2);f1(20, "小谢");auto func = [](int age, string name){cout << "年龄:" << age << ",姓名:" << name << endl;};function<void(int, string)> f2 = bind(func, placeholders::_1, placeholders::_2);f2(19, "小赵");// 类成员函数需要绑定该类的this指针 Object obj1;function<void(Object&, int, string)> f3 = bind(&Object::show, placeholders::_1, placeholders::_2, placeholders::_3);f3(obj1,17,"张三");//这里为了统一,将对象提前绑定function<void(int, string)> f4 = bind(&Object::show, obj1, placeholders::_1, placeholders::_2);f4(16, "李四");return 0;
}
在用绑定器绑定类成员函数或者成员变量的时候需要将它们所属的实例对象一并传递到绑定器函数内部。
bind的应用
改变参数位置
例如函数需要一个int和string两个参数
auto f = bind(func, placeholders::_1, placeholders::_2);
第一个参数为int,第二个为string,但是如果第一个想第一个传入string,第二个传入int
auto f = bind(func, placeholders::_2, placeholders::_1);
改变参数个数
改变参数个数主要是为了统一,便于使用函数模板,例如上述例子的部分代码
Object obj1;
function<void(Object&, int, string)> f3
= bind(&Object::show, placeholders::_1, placeholders::_2, placeholders::_3);
f3(obj1,17,"张三");
//这里为了统一,将对象提前绑定
function<void(int, string)> f4 = bind(&Object::show, obj1, placeholders::_1, placeholders::_2);
f4(16, "李四");
这里采取的是提前绑定,将对象提前绑定。
设置类成员函数为回调函数
在讲bind时上面已演示!!
相关文章:
C++之可调用对象、bind绑定器和function包装器
可调用对象在C中,可以像函数一样调用的有:普通函数、类的静态成员函数、仿函数、lambda函数、类的非静态成员函数、可被转换为函数的类的对象,统称可调用对象或函数对象。可调用对象有类型,可以用指针存储它们的地址,可…...
MongoDB--》文档查询的详细具体操作
目录 统计查询 分页列表查询 排序查询 正则的复杂条件查询 比较查询 包含查询 条件连接查询 统计查询 统计查询使用count()方法,其语法格式如下: db.collection.count(query,options) ParameterTypeDescriptionquerydocument查询选择条件optio…...
网络协议(六):网络层
网络协议系列文章 网络协议(一):基本概念、计算机之间的连接方式 网络协议(二):MAC地址、IP地址、子网掩码、子网和超网 网络协议(三):路由器原理及数据包传输过程 网络协议(四):网络分类、ISP、上网方式、公网私网、NAT 网络…...
热启动预示生态起航的Smart Finance,与深度赋能的SMART通证
2023年初加密市场的回暖,意味着各个赛道都将在新的一年里走向新的叙事。最近,我们看到GameFi赛道也在市场回暖的背景下,逐渐走出阴霾。从融资数据上看,1月获得融资的GameFi项目共12个,融资突破8000万美元,1…...
提分必练,中创教育PMP全真模拟题分享
湖南中创教育每日五题分享来啦,“日日行,不怕千万里;常常做,不怕千万事。”,每日五题我们练起来! 1、在系统测试期间,按已识别原因的类型或类别记录了失败测试的数量。项目经理首先需要从最大故…...
PID控制算法基础介绍
PID控制的概念 生活中的一些小电器,比如恒温热水器、平衡车,无人机的飞行姿态和飞行速度控制,自动驾驶等等,都有应用到 PID——PID 控制在自动控制原理中是一套比较经典的算法。 为什么需要 PID 控制器呢? 你一定用…...
Ajax 学习笔记
一、Ajax1.1 什么是AjaxAJAX Asynchronous JavaScript and XML(异步的JavaScript和XML)。Ajax是一种在无需加载整个网页的情况下,能够更新部分网页的技术,它不是一种新的编程语言,而是一种用于创建更好更快以及交互性更强的Web应用程序的技术…...
力扣解法汇总1234. 替换子串得到平衡字符串
目录链接: 力扣编程题-解法汇总_分享记录-CSDN博客 GitHub同步刷题项目: https://github.com/September26/java-algorithms 原题链接:力扣 描述: 有一个只含有 Q, W, E, R 四种字符,且长度为 n 的字符串。 假如在该…...
C++关键字之const、inline、static
C 关键字总结 1.const const是 constant 的缩写,本意是不变的、不易改变的意思。在C中用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数使用如下: //修饰普通类型变量 const int a 7; int ba;…...
【成为架构师课程系列】怎样进行概念架构(Conceptual Architecture)?
目录 前言 什么是概念架构 概念架构阶段的3个步骤 初步设计 高层分割 分层式概念服务架构 Layer:逻辑层 Tier: 物理层 按通用性分层 技术堆叠 考虑非功能需求 【禅与计算机程序设计艺术:更多阅读】 前言 胜兵先胜而后求战,败兵先站而后求胜。…...
PostgreSQL的下载安装教程(macOS、Windows)
postgresql是GIS服务端几乎不可避免要打交道的数据库。因为mysql的空间扩展真是不尽人意。所以想要学会GIS服务端知识,postgresql(下文简称pg)你是必须要会的。 首先要知道,pg是一个空间数据库,和普通数据库不同的是pg支持空间数据的存储与操作。这里所谓的空间数据一般指…...
98年的确实卷,公司新来的卷王,我们这帮老油条真干不过.....
都说00后躺平了,但是有一说一,该卷的还是卷。这不,前段时间我们公司来了个00后,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 …...
软件架构知识2-系统复杂度
架构设计的真正目的:是为了解决软件系统复杂度带来的问题,一个解决方案。 系统复杂度,如何入手: 1、通过熟悉和理解需求,识别系统复杂性所在的地方,然后针对这些复杂点进行架构设计。 2、架构设计并不是要…...
JavaSE学习day4_02 数组(超级重点)
3.数组 3.1什么是数组 数组就是存储数据长度固定的容器,存储多个数据的数据类型要一致。 3.2数组定义格式 3.2.1第一种(常用) 数据类型[] 数组名 示例: int[] arr; double[] arr; char[] arr; 3.2.2第二种(在…...
Theano教程:Python的内存管理
在写大型程序时候的一大挑战是如何保证最少的内存使用率。但是在Python中的内存管理是比较简单的。Python显示分配内存,使用引用计数系统管理对象,当指向某一个对象的引用数变为 0 的时候,该对象所占的内存就会被释放。理论上听起来很不错&am…...
Linux | Liunx安装Tomcat(Ubuntu版)
目录 一、下载并上传Tomcat压缩包到Ubuntu 1.1 下载并解压 1.2 执行 startup.sh 文件 二、验证Tomcat启动是否成功 2.1 查看启动日志 2.2 查看启动进程 三、Windows访问 Tomcat 服务 四、停止 Tomcat 服务 Tomcat是一款Web服务器,开发Web项目基本上都会用到…...
缓冲区浅析
缓冲区 程序运行输入数据时,从键盘的输入先存储到缓冲区,只有当缓冲区满或者输入回车时程序才会真正地从缓冲区读入数据 int main() {int a, b;cin >> a >> b;return 0; }in: 1 2\n 例如这里输入空格时程序没有输出,而是将空格…...
Day888.MySQL是怎么保证主备一致的 -MySQL实战
MySQL是怎么保证主备一致的 Hi,我是阿昌,今天学习记录的是关于MySQL是怎么保证主备一致的内容。 MySQL 能够成为现下最流行的开源数据库,binlog 功不可没。 在最开始,MySQL 是以容易学习和方便的高可用架构,被开发人…...
互联网舆情监测系统的发展阶段,TOOM互联网舆情监测系统有哪些?
互联网舆情监测系统是一种利用计算机技术对互联网上的大量信息进行实时监测、分析和评估的工具,旨在了解公众对某一事件、话题或品牌等的态度、情感倾向和影响力等。通过对社交媒体、论坛、新闻媒体等多个渠道的数据采集和处理,系统能够实现舆情事件的追…...
GIT命令操作大全
文章目录一、前言二、工作模块2.1 Workspace:工作区2.2 Index / Stage:暂存区2.3 Repository:本地仓库2.4Remote:远程仓库三、GIT基本配置四、GIT项目代码管理4.1 初始化git仓库4.2 提交到暂存区(stage)4.3 将暂存区的文件恢复到工…...
突破传统开发模式,亚马逊云科技助力中科院加速推动合成生物学
当数字技术成为整个社会运行的底座,生物科学也能借力云计算从诸多繁琐重复的工作中解放出来,专注于生物设计与创新。来看看亚马逊云科技如何与TIBCAS合作,推动合成生物学的发展。 明确核心需求,选择合作伙伴 TIBCAS选择与亚马逊…...
分享开放通达信l2接口的过程,开发之后怎么使用?
随着互联网的不断进步,信息技术的不断发展,通达信l2接口技术逐步成熟。那么,这些开放通达信l2接口开发的过程是怎么样的呢?期间又会遇到什么问题,开放之后又会怎么使用呢?这篇文章带你深入了解。 通达信l2接口不像一…...
33、基于51单片机老人防跌倒蜂鸣器报警系统加速度检测
背景技术 老年人出门由于身体不灵活、视力较差,容易发生跌倒,现用的老年人跌倒报警装置是通过无线对讲系统研发的,它外观精美,自动化程度高,有很强的专业性,但是,设计者忽略了一个问题…...
【项目】基于SpringBoot+Freemarker+Mybatis+MySQL+LayUI实现CRM智能办公系统
这里写目录标题CRM基本概念CRM分类模块功能描述项目代码application-dev.yml部分页面代码CRM基本概念 圈内存在这么一句话:“世上本来没有 CRM,大家的生意越来越难做了,才有了 CRM。” 在同质化竞争时代,顾客资产尤为重要&#x…...
手写识别字体的步骤是什么?怎么识别图片中的文字?
手写识别字体的步骤是什么?怎么识别图片中的文字? 1. 打开信风工具网,点击拍照按钮,选择拍图识字模式,对准需要识别的文件进行拍摄。在线工具地址: https://ocr.bytedance.zj.cn/image/ImageT…...
Mysql 存储过程
什么是存储过程? 存储过程是事先经过编译并存储在数据库的一段sql语句的集合 如何创建一个存储过程? create procedure 存储过程名称([参数列表]) beginsql语句; end#例 create procedure p1() beginselect * from t_goods;select * from t_user; end如…...
【LeetCode】每日一题(3)
目录 题目:1234. 替换子串得到平衡字符串 - 力扣(Leetcode) 题目的接口: 解题思路: 代码: 过啦!!! 写在最后: 题目:1234. 替换子串得到平衡…...
websocket学习
1.什么是websocket 1)首先websocket和http一样,是一种网络通信协议,来自HTML5的特性; 2)他可以使客户端和服务端进行双工通信,简单来说,就是双向通信:比如我们熟悉的http协议&…...
Java面试题及答案整理汇总(2023最新版)
前言 面试前还是很有必要针对性的刷一些题,很多朋友的实战能力很强,但是理论比较薄弱,面试前不做准备是很吃亏的。这里整理了很多面试常考的一些面试题,希望能帮助到你面试前的复习并且找到一个好的工作,也节省你在网…...
公司来了个卷王,我愿称之为王中王,让人崩溃
前几天我们公司一下子也来了几个新人,这些年前人是真能熬啊,本来我们几个老油子都是每天稍微加会班就打算走了,这几个新人一直不走,搞得我们也不好走。2023年春招就要开始了,最近内卷严重,各种跳槽裁员&…...
东莞网站建设费用/女生seo专员很难吗为什么
java并行执行多个任务: 最近做项目中,有个任务需要实现并发编程,个人参考了下网上的实现,自己实现了下并发方法,并且增加了简单的说明,希望的有需要的朋友有些帮助。 import java.util.UUID; import java.util.concurrent.CountDownLatch; import java.util.concurrent.E…...
wordpress4.9上传失败/小红书笔记关键词排名优化
一、前言 AlexNet是大神Alex Krizhevsky, Ilya Sutskever, Geoffrey E. Hinton三人提出的AlexNet深度卷积神经网络,摘得了2010年ILSVRC比赛的桂冠。虽然第一个典型的CNN是LeNet5网络结构,但是第一个引起大家注意的网络却是AlexNet。 二、LeNet LeNet是…...
网站后台不能修改/百度推荐现在为什么不能用了
我们在配置深度学习环境的时候,除了安装各种库和框架外,如果需要 GPU 加速,还需要配置 CUDA。那 CUDA 是什么?它的作用是什么? CUDA 编程介绍 什么是 CUDA? CUDA (Compute Unified Device Architecture) …...
中国摄影/关键seo排名点击软件
进程: 进程,线程由操作系统控制;协程(具体某一函数)由程序员操控。 curl访问网站 signal:ctrl c 结束程序 就是信号 RPC:进程在执行过程中,有一段是在远程主机上执行后再返回主机。 目前计算机工作状态&am…...
物流网站毕业设计论文/口碑营销的案例有哪些
一,自定义注解类 Target({ElementType.METHOD,ElementType.TYPE}) Retention(RetentionPolicy.RUNTIME) Inherited //继承对接口是无用的;继承的时候只会集成到类上面的注解,不会继承到方法上的注解 Documented public interface Descriptio…...
如何建设一个社交网站/百度推广开户多少钱一个月
转自: https://blog.csdn.net/u011541946/article/details/73441582 本篇介绍元素操作之清除文本,这个清除动作,我们经常用,例如在某一个网站登录界面,有时候有些设计会自动记录用户名,但是我们自动化测试&…...