C++11中的std::function和std::bind

一、可调用对象

可调用对象有以下几种定义:

  • 是一个函数指针。
  • 是一个具有operator()(运算符重载)成员函数的类对象
  • 可被转换成函数指针的类对象
  • 一个类成员函数指针

  C++中可调用对象虽然都有一个比较统一的操作形式,但是定义方法五花八门,这样就导致使用统一的方式保存可调用对象或者传递可调用对象时,会十分繁琐。C++11中提供了std::function和std::bind统一了可调用对象的各种操作。

不同的类型可能具有相同的调用形式,如:

// 普通函数
int add(int a, int b){return a+b;} // lambda表达式
auto mod = [](int a, int b){ return a % b;}// 函数对象类
struct divide{int operator()(int denominator, int divisor){return denominator/divisor;}
};

上述三种可调用对象虽然类型不同,但是共享用一种调用形式:

int(int,int)

std::function就可以将上述类型保存起来,如下:

std::function<int(int ,int)>  a = add;
std::function<int(int ,int)>  b = mod ;
std::function<int(int ,int)>  c = divide();

二、std::function

  • std::function是一个可调用对象包装器,是一个类模板,可以容纳除了类成员函数指针之外的所有可调用对象。它可以用统一的方式处理函数、函数对象、函数指针,并允许保存和延迟它们的执行。
  • 定义格式:std::function<函数类型>
  • std::function可以取代函数指针的作用,因为它可以延迟函数的执行,特别适合作为回调函数使用。它比普通函数更加的灵活和便利。

三、std::bind

  可将std::bind函数看作一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。

  std::bind将可调用对象与其参数一起进行绑定,绑定后的结果可以使用std::function保存。

std::bind主要有以下两个作用:

  • 将可调用对象和其参数绑定成一个仿函数;
  • 只绑定部分参数,减少可调用对象传入的参数。

std::bind绑定普通函数

double my_divide(double x, double y) { return x / y; }void func1(int b, char a, long c, int d)
{cout << b << " " << a << " " << c << " " << d << "\n";
}int main()
{auto fn_half = std::bind(my_divide, std::placeholders::_1, 2);cout << fn_half(10) << "\n"; //输出结果: 5std::function<void(int, long)> func = std::bind(func1, std::placeholders::_1, 'c', std::placeholders::_2, 111);//输出结果:10 c 20 111func(10, 20);return 0;
}
  • bind的第一个参数是函数名,普通函数做实参时,会隐式转换成函数指针。因此std::bind(my_divide,std::placeholders::_1,2)等价于std::bind(&my_divide,std::placeholders::_1,2)。
  • std::placeholders::_1表示占位符,即对my_divide的第一个形参进行占位,将my_divide函数适配成一个形参的函数。

std::bind绑定一个成员函数

struct Foo
{void PrintSum(int n1, int n2){cout << n1 / n2 << "\n";}int data = 10;
};int main()
{Foo foo;auto f = std::bind(&Foo::PrintSum, &foo, 95, std::placeholders::_1);//PrintSum的第二个参数占位f(5); //输出结果:19return 0;
}
  • bind绑定类成员函数时,第一个参数表示对象的成员函数的指针,第二个参数表示对象的地址。
  • 第一个参数必须显式的指定&Foo::PrintSum,因为编译器不会将对象的成员函数隐式转换成函数指针,所以必须在Foo::PrintSum前添加&。
  • 使用对象成员函数的指针时,必须要知道指针属于哪个对象,因此第二个参数为对象的地址&foo。

std::bind绑定一个引用参数

  默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中。但是,与lambda类似,有时对有些绑定的参数希望以引用的方式传递,或是要绑定参数的类型无法拷贝。如果需要bind使用引用的方式赋值,则需要配合std::ref。

void print(int &a, int &b)
{a++;b++;cout << "函数调用:a=" << a << ",b =" << b << "\n";
}int main()
{int a = 1;int b = 2;print(a, b);auto func2 = std::bind(print, a, std::ref(b));cout << "调用前:a = " << a << ",b =" << b << "\n";func2();cout << "调用后:a = " << a << ",b =" << b << "\n";return 0;
}

  调用的时候,尽管函数传入的方式都是引用,但是略有不同。参数a使用的是传统的方式,参数b采用的是std::ref的方式。输出结果进一步验证:默认情况下,bind的那些不是占位符的参数被拷贝到bind返回的可调用对象中,即以拷贝的方式存入bind 的返回的可调用对象中。

参考文章

https://www.jianshu.com/p/f191e88dcc80

https://www.cnblogs.com/pandamohist/p/14223254.html

C++11中的std::function和std::bind相关推荐

  1. C++中std::function和std::bind

    1.可调用对象 可调用对象有一下几种定义: 是一个函数指针,参考 C++ 函数指针和函数类型: 是一个具有operator()成员函数的类的对象: 可被转换成函数指针的类对象: 一个类成员函数指针: ...

  2. 【C++】C++11的std::function和std::bind用法详解

    在设计回调函数的时候,无可避免地会接触到可回调对象.在C++11中,提供了std::function和std::bind两个方法来对可回调对象进行统一和封装. 可调用对象 C++中有如下几种可调用对象 ...

  3. C++11 FAQ中文版:std::function 和 std::bind

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

  4. std::function和std::bind

    std::function和std::bind std::function 可调用对象 是一个函数指针 是一个具有operator()成员函数的类和对象 可被转换成函数指针的类对象: 一个类成员函数指 ...

  5. 可调用对象、std::function、std::bind

    可调用对象.std::function.std::bind 仿函数functors function adapter bind(C++11) 函数适配器:bind2nd 仿函数适配器(mem_fun/ ...

  6. std::function和std::bind用法

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

  7. 【c++】24.std::function和std::bind详解

    1. 可调用对象 查看全文 http://www.taodudu.cc/news/show-494578.html 相关文章: [c++]26.浅谈"事件驱动".select.po ...

  8. C++11中的std::function

    文章转载自:http://www.jellythink.com/archives/771 看看这段代码 先来看看下面这两行代码: std::function<void(EventKeyboard ...

  9. 概率论中指数分布介绍及C++11中std::exponential_distribution的使用

    指数分布:在深度学习中,我们经常会需要一个在x=0点处取得边界点(sharp point)的分布.为了实现这一目的,我们可以使用指数分布(exponential distribution): p(x; ...

  10. 概率论中高斯分布(正态分布)介绍及C++11中std::normal_distribution的使用

    高斯分布:最常用的分布是正态分布(normal distribution),也称为高斯分布(Gaussian distribution): 正态分布N(x;μ,σ2)呈现经典的"钟形曲线&q ...

最新文章

  1. @Transient不起作用的问题
  2. wxWidgets:wxTreeCtrl 示例
  3. ML.NET Cookbook:(17)如何在分类数据上训练模型?
  4. html5如何绘制饼图,如何在HTML5中创建“饼图”?
  5. win32开发(按键消息)
  6. Memcache 提高缓存命中率
  7. Java内存溢出定位和解决方案(new)
  8. 跟大家分享一下牛人常用的资源(牛客网 )!
  9. 毒液组学-多组学关联分析大全
  10. python列表如何求增长率_python如何计算环比增长率
  11. AcWing 143. 最大异或对 —— 神奇的二进制
  12. 我热爱计算机作文450字,热爱音乐的我作文450字
  13. 判定平方数(Python)
  14. HIS Metrics
  15. 苏黎世联邦理工学院计算机博士去向,2019年5月31日学术报告(李文 研究员,瑞士苏黎世联邦理工学院)...
  16. 45 大事件项目 => [01] 后台管理项目ajax练习
  17. Tomcat的server启动
  18. 夜半加班之附魔吃药篇!
  19. 企业宣传片如何快速接入微信公众号中?
  20. 【愚公系列】2023年01月 Java教学课程 005-关键字

热门文章

  1. 【文末福利】聊天机器人的几种主要架构实现
  2. 干货 | 那些高产的学者都是怎样工作的?
  3. 《MYSQL必知必会》—10~13.创建计算字段、使用数据处理函数、使用聚集函数汇总数据,使用GROUP BY与HAVING分组数据及过滤
  4. 李宏毅自然语言处理——成分句法分析
  5. HarmonyOS IoT首著,走进万物互联的世界!
  6. NFC:Arduino、Android与PhoneGap近场通信
  7. 海量数据挖掘MMDS week3:社交网络之社区检测:高级技巧
  8. Ubuntu18.04配置Jupyter
  9. matlab min函数_数学建模与MATLAB非线性规划
  10. 8086cpu学习笔记(3):寻址方式