C++11 学习笔记 std::function和bind绑定器

一.std::function

C++中的可调用对象虽然具有比较统一操作形式(除了类成员指针之外,都是后面加括号进行调用),但定义方法五花八门。为了统一泛化函数对象,函数指针,引用函数,成员函数的指针的各种操作,让我们可以按更统一的方式写出更加泛化的代码,C++11推出了std::function。

  std::function是可调用对象的包装器。它是一个类模板,可以容纳除了类成员(函数)指针之外的所有可调用对象。通过指定它的模板参数,它可以用统一的方式处理函数,函数对象,函数指针,并允许保存和延迟执行它们。

  1. #1include <iostream>
  2. #include <functional>
  3.  
  4. using namespace std;
  5.  
  6. void func(void){
  7. cout << __FUNCTION__ << "(" << a << ") ->: ";
  8. }
  9.  
  10. class Foo
  11. {
  12. public:
  13. static int foo_func(int a){
  14. cout << __FUNCTION__ << "(" << a << ") ->: ";
  15. return a;
  16. }
  17. };
  18.  
  19. class bar
  20. {
  21. public:
  22. int operator()(int a){
  23. cout << __FUNCTION << "(" << a << ") ->: ";
  24. return a;
  25. }
  26. };
  27.  
  28. int main(){
  29. //绑定一个普通函数
  30. std::function<void(void)> fry = func;
  31. fr1();
  32.  
  33. //绑定一个类的静态成员函数
  34. std::function<int(int)> fr2 = Foo::foo_func;
  35. cout << fr2() << endl;
  36.  
  37. //绑定一个仿函数
  38. Bar bar;
  39. fr2 = bar;
  40. cout << fr2() <<endl;
  41.  
  42. return ;
  43. }

std::function的使用方法:我们给std::function填入合适的函数签名(即一个函数类型,只需要包括返回值和参数表)之后,它就变成了一个可以容纳所有这一类调用方式的“函数包装器”。

  1. #include <iostream>
  2. #include <functional>
  3.  
  4. using namespace std;
  5.  
  6. class A
  7. {
  8. public:
  9. A(const std::function<void()>& f){
  10. :callback_(f){}
  11.  
  12. void notify(void){
  13. callback_();
  14. }
  15. private:
  16. std::function<void()> callback_;
  17. };
  18.  
  19. class Foo
  20. {
  21. public:
  22. void operator()(void){
  23. cout << __FUNCTION__<< endl;
  24. }
  25. };
  26.  
  27. int main(){
  28. Foo foo;
  29. A aa(foo);
  30. aa.notify();
  31.  
  32. return ;
  33. }

从上面的例子看,std::function可以取代函数指针的作用。因为它可以保存函数延迟执行,所以比较适合作为回调函数,也可以把它看做类似于C#中特殊的委托(只有一个成员的委托)。

  1. #include <iostream>
  2. #include <functional>
  3.  
  4. using namespace std;
  5.  
  6. void call_when_even(int x, const std::function<void(int)>& f){
  7. if(!(x & )){
  8. f(x);
  9. }
  10. }
  11.  
  12. void output(int x){
  13. cout << x <<" ";
  14. }
  15.  
  16. int main(void){
  17. for(int i=;i<;i++){
  18. call_when_even(i, output);
  19. }
  20. cout<<endl;
  21.  
  22. return ;
  23. }

std::function还可以作为函数入参,这样可以在函数外部控制函数的内部行为了,让我们的函数变得更加灵活。

二.std::bind绑定器

  std::bind用来将可调用对象与其参数一起进行绑定。绑定后的结果可以使用std::function进行保存,并延迟调用到任何我们需要的时候。通俗来讲,它主要有两大作用:

  1).将可调用对象与其参数一起绑定成一个仿函数。

  2).将多元(参数个数为n,n>1)可调用对象转成一元或者(n-1)元可调用对象,即只绑定部分参数。

  function模板类和bind模板函数,都可以实现类似函数指针的功能,但却却比函数指针更加灵活,特别是函数指向类的非静态成员函数时。

  1).std::function可以绑定到全局函数/类静态成员函数(类静态成员函数与全局函数没有区别)。

  2).绑定到类的非静态成员函数,则需要使用std::bind。

  1. #include <iostream>
  2. #include <functional>
  3.  
  4. using namespace std;
  5.  
  6. void call_when_even(int x, const std::function<void(int)>& f){
  7. if(!(x & )){
  8. f(x);
  9. }
  10. }
  11.  
  12. void output(int x){
  13. cout << x << " ";
  14. }
  15.  
  16. void output_add_2(int x){
  17. cout << x + << " ";
  18. }
  19.  
  20. int main(){
  21. {
  22. auto fr = std::bind(output, std::placeholders::_1);
  23. for(int i=;i<;i++){
  24. call_when_even(i, fr);
  25. }
  26. cout << endl;
  27. }
  28.  
  29. {
  30. auto fr = std::bind(output_add_2, std::placeholders::_1);
  31. for(int i=;i<;i++){
  32. call_when_even(i, fr);
  33. }
  34. cout << endl;
  35. }
  36.  
  37. return ;
  38. }

"std::placeholders::_1"是一个占位符对象,用于表示当函数output(output_add_2)通过函数fr进行调用时,函数fr的第一个参数在函数output(output_add_2)的参数列表中的位置。

下面是两个样例:

  1. #include <iostream>
  2. #include <functional>
  3.  
  4. using namespace std;
  5.  
  6. class A
  7. {
  8. public:
  9. int i_=;
  10.  
  11. void output(int x, int y){
  12. cout << x << " " << y <<endl;
  13. }
  14. };
  15.  
  16. int main(){
  17. A a;
  18. std::function<void(int, int)> fr = std::bind(&A::output, &a, std::placeholders::_1,std::placeholders::_2);
  19. fr(,);
  20.  
  21. std::function<int&(void)> fr_i = std::bind(&A::i_, &a);
  22. fr_i() = ;
  23. cout << a.i_ << endl;
  24.  
  25. return ;
  26. }
  1. //使用组合bind函数,找出集合中大于5小于10的元素个数
  2. #include <iostream>
  3. #include <functional>
  4.  
  5. using namespace std;
  6.  
  7. auto f = std::bind(std::logical_and<bool>(),std::bind(std::greater<int>(),_1,),std::bind(std::less_equal<int>(), _1, ));
  8.  
  9. int main(){
  10. set<int> se={,,,,,,,,};
  11. int count = std::count_if(se.begin(), se.end(), f);
  12. cout << count <<endl;
  13.  
  14. return ;
  15. }

std::bind需要注意的一些事项:(http://www.cnblogs.com/slysky/p/3822640.html)

1).std::bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数,是pass-by-value的

2).对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。placeholder是pass-by-reference的

3).bind的返回值是可调用实体,可以直接赋给std::function对象

4).对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的

5).类的this可以通过对象或者指针来绑定

C++11 学习笔记 std::function和bind绑定器的更多相关文章

  1. c++11——std::function和bind绑定器

    c++11中增加了std::function和std::bind,可更加方便的使用标准库,同时也可方便的进行延时求值. 可调用对象 c++中的可调用对象存在以下几类: (1)函数指针 (2)具有ope ...

  2. 第11课 std::bind和std::function(2)_std::bind绑定器

    1. 温故知新:std::bind1st和std::bind2nd (1)bind1st.bind2nd首先它们都是函数模板,用于将参数绑定到可调用对象(如函数.仿函数等)的第1个或第2个参数上. ( ...

  3. C++11学习笔记之三lamda表达式,std::function, std::bind

    //lamda //first lamda [] {}; // second lamda []() //or no need () when paramater is null { std::cout ...

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

    看看这段代码 先来看看下面这两行代码: std::function<void(EventKeyboard::KeyCode, Event*)> onKeyPressed; std::fun ...

  5. 【转】C++11中的std::function

    原文地址:http://www.jellythink.com/archives/771 看看这段代码 先来看看下面这两行代码: std::function<void(EventKeyboard: ...

  6. C++中的仿函数,std::function和bind()的用法

    1.仿函数:又叫std::function,是C++中的一个模板类 2.C语言中的函数指针: int  add(int a,int b) { return a+b; } typedef int (*f ...

  7. javascript学习笔记 - 引用类型 Function

    五 Function类型 每个函数都时Function类型的实例.函数也是对象. 声明函数: function func_name () {} //javascript解析器会在程序执行时率先读取函数 ...

  8. tensorflow学习笔记——自编码器及多层感知器

    1,自编码器简介 传统机器学习任务很大程度上依赖于好的特征工程,比如对数值型,日期时间型,种类型等特征的提取.特征工程往往是非常耗时耗力的,在图像,语音和视频中提取到有效的特征就更难了,工程师必须在这 ...

  9. Noah的学习笔记之Python篇:装饰器

    Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang  (http://www.cnblogs.com/noahzn/) ...

随机推荐

  1. Spring -09 -在Spring工程 中加载 properties 文件 -为某个属性添加注解赋初值

    1.在src 下新建 xxx.properties 文件,不要任意加空格,注明jdbc等标识名!2.在spring 配置文件中先引入xmlns:context,在下面添加2.1如果需要记载多个配置文件 ...

  2. P1983 车站分级[拓扑]

    题目描述 一条单向的铁路线上,依次有编号为 1, 2, -, n1,2,-,n的 nn个火车站.每个火车站都有一个级别,最低为 11 级.现有若干趟车次在这条线路上行驶,每一趟都满足如下要求:如果这趟 ...

  3. “挂起”bug处理执行方案

    目的:避免bug状态改为挂起后,就无人问津,导致一直未得到解决.因而影响用户的使用与产品质量较差.

  4. HDP 大数据平台搭建

    一.概述 Apache Ambari是一个基于Web的支持Apache Hadoop集群的供应.管理和监控的开源工具,Ambari已支持大多数Hadoop组件,包括HDFS.MapReduce.Hiv ...

  5. learning java 正则表达式

    var regStr = "Java is very good"; Matcher m = Pattern.compile("\\w+").matcher(re ...

  6. aix 10代oracle zabbix2.4.4 日志监控

    同一类型的监控项,zabbix 2.4的客户端也支持日志监控,可是在参数个数上有问题,如果把所有参数都放满,监控项会提示too mant parameters,无法 生效取数据, 对于不同的正则式.m ...

  7. 洛谷 P1823 [COI2007] Patrik 音乐会的等待 题解

    P1823 [COI2007] Patrik 音乐会的等待 题目描述 N个人正在排队进入一个音乐会.人们等得很无聊,于是他们开始转来转去,想在队伍里寻找自己的熟人.队列中任意两个人A和B,如果他们是相 ...

  8. Three.js实现滚轮放大展现不同的模型

    目录 Three.js实现滚轮放大展现不同的模型 修改OrbitControls.js的源码 OrbitControls在透视相机(PerspectiveCamera)的控制原理 具体实现 Three ...

  9. LOJ#2983. 「WC2019」数树 排列组合,生成函数,多项式,FFT

    原文链接www.cnblogs.com/zhouzhendong/p/LOJ2983.html 前言 我怎么什么都不会?贺忙指导博客才会做. 题解 我们分三个子问题考虑. 子问题0 将红蓝共有的边连接 ...

  10. JetBrains CLion 2019 for Mac(智能C和C++编辑器)中英文如何切换完整教程

    右键显示包内容,进入目录,contents/lib,删除resources_zh.jar,重启即可. 参考: https://blog.csdn.net/qq_45179462/article/det ...