【浅析C++11】std::function和std::bind
std::function可调用对象包装器
C++可调用对象(Callable Objects)定义如下:
- 函数指针:与C语言一致;
- 类成员函数指针;
- 仿函数(functor):也成函数对象,重载
operator()运算符的类/结构体对象; - lambda表达式。
std::function是Callable Objects的包装器(Wrapper),可接收除了类成员函数指针以外的任意Callable Objects。std::function可用来处理函数回调,与C语言函数指针类似,允许保存以上Callable Objects,并延迟执行它们,但它可保存除函数指针外的其他Callable Objects,因此它比C语言更强大。
当我们为std::function具现化一个函数签名(函数类型,包括返回值和参数列表),它就成为一个可容纳所有这类调用的函数包装器。
std::function基本用法
#include <iostream>
#include <functional> // std::function
// global function
void func(void) {
std::cout << __FUNCTION__ << std::endl;
}
class Foo {
public:
// class static function
static int foo_func(int a) {
std::cout << __FUNCTION__ << "(" << a << "):";
return a;
}
// class non-static member function
int foo_func_nonstatic(int a) {
std::cout << __FUNCTION__ << "(" << a << "):";
return a;
}
};
class Bar {
public:
// functor
int operator()(int a) {
std::cout << __FUNCTION__ << "(" << a << "):";
return a;
}
};
int main() {
// 传入合适函数签名给std::function模板参数即可绑定对应签名的
// 普通函数或
// 类静态成员函数或
// 借助std::bind绑定类非静态成员函数
std::function<void(void)> func1 = func;
std::function<int(int)> func2 = Foo::foo_func;
Foo foo;
std::function<int(int)> func3 = std::bind(&Foo::foo_func_nonstatic, &foo,
std::placeholders::_1);
// 然后,直接像函数一样调用
func1(); // func
std::cout << func2(1) << std::endl; // foo_func(1):1
std::cout << func3(11) << std::endl; // foo_func_nonstatic(11):11
// 当函数签名一致时,func2可像一个变量一样复用
// Bar重载了operator()即成为functor,可直接包装到std::function
Bar bar;
func2 = bar;
std::cout << func2(2) << std::endl; // operator()(2):2
// 也可绑定lambda表达式
auto func_lambda = [](int a){
std::cout << "bind lambda sample(" << a << ")" << std::endl;
};
func_lambda(3); // bind lambda sample(3)
return 0;
}
既然std::function可作为左值接收函数对象,那么它可作为函数的形参;且std::function可绑定函数指针,实现函数的延迟执行,所以std::function可取代std::function作为回调函数。
std::function实现回调机制的例子如下:
#include <iostream>
#include <functional> // std::function
// 任意可调用对象,如普通全局函数
void func_callback(int a) {
std::cout << __FUNCTION__ << ":Output, a=" << a << std::endl;
}
class Foo {
public:
explicit Foo(std::function<void(int)> cb)
:cb_(cb), a_(0) {
}
~Foo() = default;
// setter
void set_a(int a) {
a_ = a;
}
void OutputCallback() {
cb_(a_);
}
private:
std::function<void(int)> cb_;
int a_;
};
int main() {
// 实例化Foo,并参数注入回调函数
// 处理
// 回调输出处理结果
Foo foo(func_callback);
foo.set_a(1);
foo.OutputCallback(); // func_callback:Output, a=1
return 0;
}
以上,介绍了std::function绑定Callable Objects的用法,并以一个实例演示了std::function作为函数回调的例子;其中,func_callback回调函数参数为int型,在实际应用如人脸智能分析中,人脸分析信息结构体指针可作为回调函数参数,该函数可输出人脸识别结果;Foo类可为人脸分析相关类,OutputCallback可能在该类某个人脸分析线程中被调用,分析得到的结果可调用OutputCallback回调输出给提供func_callback的用户。
注:C++11提供的std::function可替代C语言中函数指针作为回调函数,前者是C++编程风格,后者是C编程风格。
C/C++回调机制在服务器端并发编程和游戏领域应用广泛,著名2d游戏框架Cocos2dx大量使用回调机制,提供了常用的回调宏如下所示,更多回调机制可参考Cocos2dx开源源码。
// Cocos2dx new callbacks based on C++11
//
// __selector__:回调函数指针
// __target__:回调对象指针
// ##__VA_ARGS__:可变参数列表
// std::placeholders::_1:不定参数1,调用时由调用函数的参数传入
// std::placeholders::_2:不定参数2,调用时由调用函数的参数传入
// std::placeholders::_3:不定参数3,调用时由调用函数的参数传入
#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)
std::function/std::bind与抽象工厂、工厂方法的一点思考
TODO...
【浅析C++11】std::function和std::bind的更多相关文章
- C++11 std::function、std::bind和lambda表达式
参考博客: C++可调用对象详解-https://www.cnblogs.com/Philip-Tell-Truth/p/5814213.html 一.关于std::function与std::bin ...
- C++11新特性应用--实现延时求值(std::function和std::bind)
说是延时求值,注意还是想搞一搞std::function和std::bind. 之前博客<C++11新特性之std::function>注意是std::function怎样实现回调函数. ...
- c++11 符号修饰与函数签名、函数指针、匿名函数、仿函数、std::function与std::bind
一.符号修饰与函数签名 1.符号修饰 编译器将c++源代码编译成目标文件时,用函数签名的信息对函数名进行改编,形成修饰名.GCC的C++符号修饰方法如下: 1)所有符号都以_z开头 2)名字空间的名字 ...
- C++ 中std::function 、std::bind的使用和lambda的使用
std::function是可调用对象的包装器:std::bind是将可点用对象和其参数一起进行绑定,且绑定后的结果可以使用std::function对象进行保存,并延迟调用到需要调用的时候: 在C+ ...
- std::function,std::bind
std::function 和 std::bind 标准库函数bind()和function()定义于头文件中(该头文件还包括许多其他函数对象),用于处理函数及函数参数.bind()接受一个函数(或者 ...
- C++11之std::function和std::bind
std::function是可调用对象的包装器,它最重要的功能是实现延时调用: #include "stdafx.h" #include<iostream>// std ...
- 转 C++11之std::function和std::bind
std::function是可调用对象的包装器,它最重要的功能是实现延时调用: #include "stdafx.h" #include<iostream>// std ...
- C/C++ C++ 11 std::function和std::bind用法
std::bind() std::bind 主要用于绑定生成目标函数,一般用于生成的回调函数,cocos的回退函数都是通过std::bind和std::function实现的.两个点要明白: 1.绑定 ...
- std::function与std::bind 函数指针
function模板类和bind模板函数,使用它们可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类 的非静态成员函数时. std::function可以绑定到全局函数/类静态成员 ...
随机推荐
- zabbix之自定义告警
zabbix支持内置的告警类型.email,sms,等 有时候需要自定义类型的. [其他微信,钉钉都差不多方式,只是脚本不一样] 自定义告警类型[自定义邮件] 编写自定义脚本,并测试成功. [脚本需要 ...
- 2019.6.28 校内测试 T3 【音乐会】道路千万条
大眼一看最下面的题意解释的话,发现这和洛谷P1310表达式的值挺像的,大概都是给定一些运算符号,让最后的表达式为true的概率,为false的概率啥的QwQ~: 然后这个题嘛?就是在所有的运算符中提溜 ...
- 微信小程序开发-踩坑
异步请求处理 详情描述: 微信小程序的wx.request({})请求时异步处理,以下代码 wx.reuest({ url:"https://XXXA", method:" ...
- 小程序开发:用原生还是选框架(wepy/mpvue/uni-app/taro)?
小程序开发:用原生还是选框架(wepy/mpvue/uni-app/taro)? 自 2017-1-9微信小程序诞生以来,历经2年多的迭代升级,已有数百万小程序上线,成为继Web.iOS.Androi ...
- fatal: unable to access 'https://github.com/Homebrew/brew/'
最近安装 Homebrew 遇到的坑,总结一下. 我的 Mac 版本是 10.13.6. 首先安装 Homebrew /usr/bin/ruby -e "$(curl -fsSL https ...
- 【spring源码分析】IOC容器初始化——查漏补缺(二)
前言:在[spring源码分析]IOC容器初始化(八)中多次提到了前置处理与后置处理,本篇文章针对此问题进行分析.Spring对前置处理或后置处理主要通过BeanPostProcessor进行实现. ...
- php中strlen()和mb_strlen()函数
php中strlen()和mb_strlen()函数 一.总结 一句话总结: mb_strlen()函数 的作用是 通过不同的编码计算字符串的长度: 比如 echo mb_strlen('中文a字1符 ...
- 阶段5 3.微服务项目【学成在线】_day05 消息中间件RabbitMQ_3.RabbitMQ研究-工作原理
Producer生产者 Consumer:消费者 组成部分说明如下: Broker:消息队列服务进程,此进程包括两个部分:Exchange和Queue. Exchange:消息队列交换机,按一定的规则 ...
- 防止sshd服务被暴力破解
方法有很多种,这里介绍两种. (1).配置安全的shhd设置 不允许root用户直接登录到系统,添加一个普通用户,必要时再切换到root用户. 修改默认端口号. 不允许密码登录,只能通过密钥登录系统. ...
- 数学建模python matlab 编程(疾病传播模型)
例12:一只游船上有800(1000)人,一名游客不慎患传染病,12(10)小时后有3人发病,由于船上不能及时隔离,问经过60(30)小时,72小时,患此病的人数.(与人口模型和Logistic模型类 ...