【浅析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...
上一篇: 明朝倭患的主体不是日本人 为何还要称之为“倭寇”呢
下一篇: 第2章学习小结