std::function可调用对象包装器

C++可调用对象(Callable Objects)定义如下:

  1. 函数指针:与C语言一致;
  2. 类成员函数指针;
  3. 仿函数(functor):也成函数对象,重载operator()运算符的类/结构体对象;
  4. lambda表达式。

std::function是Callable Objects的包装器(Wrapper),可接收除了类成员函数指针以外的任意Callable Objects。std::function可用来处理函数回调,与C语言函数指针类似,允许保存以上Callable Objects,并延迟执行它们,但它可保存除函数指针外的其他Callable Objects,因此它比C语言更强大。

当我们为std::function具现化一个函数签名(函数类型,包括返回值和参数列表),它就成为一个可容纳所有这类调用的函数包装器。

std::function基本用法

  1. #include <iostream>
  2. #include <functional> // std::function
  3. // global function
  4. void func(void) {
  5. std::cout << __FUNCTION__ << std::endl;
  6. }
  7. class Foo {
  8. public:
  9. // class static function
  10. static int foo_func(int a) {
  11. std::cout << __FUNCTION__ << "(" << a << "):";
  12. return a;
  13. }
  14. // class non-static member function
  15. int foo_func_nonstatic(int a) {
  16. std::cout << __FUNCTION__ << "(" << a << "):";
  17. return a;
  18. }
  19. };
  20. class Bar {
  21. public:
  22. // functor
  23. int operator()(int a) {
  24. std::cout << __FUNCTION__ << "(" << a << "):";
  25. return a;
  26. }
  27. };
  28. int main() {
  29. // 传入合适函数签名给std::function模板参数即可绑定对应签名的
  30. // 普通函数或
  31. // 类静态成员函数或
  32. // 借助std::bind绑定类非静态成员函数
  33. std::function<void(void)> func1 = func;
  34. std::function<int(int)> func2 = Foo::foo_func;
  35. Foo foo;
  36. std::function<int(int)> func3 = std::bind(&Foo::foo_func_nonstatic, &foo,
  37. std::placeholders::_1);
  38. // 然后,直接像函数一样调用
  39. func1(); // func
  40. std::cout << func2(1) << std::endl; // foo_func(1):1
  41. std::cout << func3(11) << std::endl; // foo_func_nonstatic(11):11
  42. // 当函数签名一致时,func2可像一个变量一样复用
  43. // Bar重载了operator()即成为functor,可直接包装到std::function
  44. Bar bar;
  45. func2 = bar;
  46. std::cout << func2(2) << std::endl; // operator()(2):2
  47. // 也可绑定lambda表达式
  48. auto func_lambda = [](int a){
  49. std::cout << "bind lambda sample(" << a << ")" << std::endl;
  50. };
  51. func_lambda(3); // bind lambda sample(3)
  52. return 0;
  53. }

既然std::function可作为左值接收函数对象,那么它可作为函数的形参;且std::function可绑定函数指针,实现函数的延迟执行,所以std::function可取代std::function作为回调函数。

std::function实现回调机制的例子如下:

  1. #include <iostream>
  2. #include <functional> // std::function
  3. // 任意可调用对象,如普通全局函数
  4. void func_callback(int a) {
  5. std::cout << __FUNCTION__ << ":Output, a=" << a << std::endl;
  6. }
  7. class Foo {
  8. public:
  9. explicit Foo(std::function<void(int)> cb)
  10. :cb_(cb), a_(0) {
  11. }
  12. ~Foo() = default;
  13. // setter
  14. void set_a(int a) {
  15. a_ = a;
  16. }
  17. void OutputCallback() {
  18. cb_(a_);
  19. }
  20. private:
  21. std::function<void(int)> cb_;
  22. int a_;
  23. };
  24. int main() {
  25. // 实例化Foo,并参数注入回调函数
  26. // 处理
  27. // 回调输出处理结果
  28. Foo foo(func_callback);
  29. foo.set_a(1);
  30. foo.OutputCallback(); // func_callback:Output, a=1
  31. return 0;
  32. }

以上,介绍了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开源源码。

  1. // Cocos2dx new callbacks based on C++11
  2. //
  3. // __selector__:回调函数指针
  4. // __target__:回调对象指针
  5. // ##__VA_ARGS__:可变参数列表
  6. // std::placeholders::_1:不定参数1,调用时由调用函数的参数传入
  7. // std::placeholders::_2:不定参数2,调用时由调用函数的参数传入
  8. // std::placeholders::_3:不定参数3,调用时由调用函数的参数传入
  9. #define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)
  10. #define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)
  11. #define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)
  12. #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的更多相关文章

  1. C++11 std::function、std::bind和lambda表达式

    参考博客: C++可调用对象详解-https://www.cnblogs.com/Philip-Tell-Truth/p/5814213.html 一.关于std::function与std::bin ...

  2. C++11新特性应用--实现延时求值(std::function和std::bind)

    说是延时求值,注意还是想搞一搞std::function和std::bind. 之前博客<C++11新特性之std::function>注意是std::function怎样实现回调函数. ...

  3. c++11 符号修饰与函数签名、函数指针、匿名函数、仿函数、std::function与std::bind

    一.符号修饰与函数签名 1.符号修饰 编译器将c++源代码编译成目标文件时,用函数签名的信息对函数名进行改编,形成修饰名.GCC的C++符号修饰方法如下: 1)所有符号都以_z开头 2)名字空间的名字 ...

  4. C++ 中std::function 、std::bind的使用和lambda的使用

    std::function是可调用对象的包装器:std::bind是将可点用对象和其参数一起进行绑定,且绑定后的结果可以使用std::function对象进行保存,并延迟调用到需要调用的时候: 在C+ ...

  5. std::function,std::bind

    std::function 和 std::bind 标准库函数bind()和function()定义于头文件中(该头文件还包括许多其他函数对象),用于处理函数及函数参数.bind()接受一个函数(或者 ...

  6. C++11之std::function和std::bind

    std::function是可调用对象的包装器,它最重要的功能是实现延时调用: #include "stdafx.h" #include<iostream>// std ...

  7. 转 C++11之std::function和std::bind

    std::function是可调用对象的包装器,它最重要的功能是实现延时调用: #include "stdafx.h" #include<iostream>// std ...

  8. C/C++ C++ 11 std::function和std::bind用法

    std::bind() std::bind 主要用于绑定生成目标函数,一般用于生成的回调函数,cocos的回退函数都是通过std::bind和std::function实现的.两个点要明白: 1.绑定 ...

  9. std::function与std::bind 函数指针

    function模板类和bind模板函数,使用它们可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类 的非静态成员函数时. std::function可以绑定到全局函数/类静态成员 ...

随机推荐

  1. c#递归读取菜单树

    1.查询菜单节点下所有子节点id List<sys_module> menus = new List<sys_module>() { }; public async Task& ...

  2. maven项目无法查看类库的源码

    一个Maven项目有两种类库,分别是JRE System Libaray和Maven Dependencies. JRE System Libaray 一般有两种方法指定. 1.由pom.xml中的m ...

  3. codeforces gym #101161F-Dictionary Game(字典树+树上删边游戏)

    题目链接: http://codeforces.com/gym/101161/attachments 题意: 给一个可以变化的字典树 在字典树上删边 如果某条边和根节点不连通那么这条边也删除 谁没得删 ...

  4. JavaWeb_(Mybatis框架)关联查询_六

    系列博文: JavaWeb_(Mybatis框架)JDBC操作数据库和Mybatis框架操作数据库区别_一 传送门 JavaWeb_(Mybatis框架)使用Mybatis对表进行增.删.改.查操作_ ...

  5. Java并发指南4:Java中的锁 Lock和synchronized

    Java中的锁机制及Lock类 锁的释放-获取建立的happens before 关系 锁是java并发编程中最重要的同步机制.锁除了让临界区互斥执行外,还可以让释放锁的线程向获取同一个锁的线程发送消 ...

  6. puppeteer爬虫服务

    爬虫文件 baidu.js const puppeteer = require("puppeteer"); const path = require('path'); const ...

  7. 第11组 Beta冲刺(5/5)

    第11组 Beta冲刺(5/5)   队名 不知道叫什么团队 组长博客 https://www.cnblogs.com/xxylac/p/12031050.html 作业博客 https://edu. ...

  8. [java]察看两个日期间差多少秒/小时/天

    Java 中Date类getTime()的方法返回从1970-1-1以来的毫秒数,这是下面函数运行的基础. package com.example.demo; import java.text.Par ...

  9. js es6遍历对象的6种方法(应用中推荐前三种)

        javaScript遍历对象总结 1.for … in 循环遍历对象自身的和继承的可枚举属性(循环遍历对象自身的和继承的可枚举属性(不含Symbol属性).). 2.使用Object.keys ...

  10. ZXHN H218N 超级管理员账号

    telecomadmin nE7jA%5m cmcc空格cmcc空格cmccaDm8H%MdA