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

std::function可以绑定到全局函数/类静态成员函数(类静态成员函数与全局函数没有区别),如果要绑定到类的非静态成员函数,则需要使用std::bind。

标准库函数bind()和function()定义于头文件<functional>中(该头文件还包括许多其他函数对象),用于处理函数及函数参数。

std::bind绑定器

  • 将函数、成员函数和闭包转成function函数对象
  • 将多元(n>1)函数转成一元函数或者(n-1)元函数。

bind()接受一个函数(或者函数对象,或者任何你可以通过"(...)"符号调用的事物),生成一个其有某一个或多个函数参数被“绑定”或重新组织的函数对象。(译注:顾名思义,bind()函数的意义就像它的函数名一样,是用来绑定函数调用的某些参数的。)例如:

1         int f(int, char, double);
2         auto ff = bind(f, _1, 'c', 1.2);    // 绑定f()函数调用的第二个和第三个参数,返回一个新的函数对象为ff,它只带有一个int类型的参数
3         int x = ff(7);                //  f(7, 'c', 1.2);

参数的绑定通常称为"Currying"(译注:Currying---“烹制咖喱烧菜”,此处意指对函数或函数对象进行加工修饰操作), "_1"是一个占位符对象,用于表示当函数f通过函数ff进行调用时,函数ff的第一个参数在函数f的参数列表中的位置。第一个参数称为"_1", 第二个参数为"_2",依此类推。例如:

1         int f(int, char, double);
2         auto frev = bind(f, _3, _2, _1);        // 翻转参数顺序
3         int x = frev(1.2, 'c', 7);            // f(7, 'c', 1.2);

此处,auto关键字节约了我们去推断bind返回的结果类型的工作。
    我们无法使用bind()绑定一个重载函数的参数,我们必须显式地指出需要绑定的重载函数的版本:

1         int g(int);
2         double g(double);
3
4         auto g1 = bind(g, _1);                // 错误:调用哪一个g() ?
5         auto g2 = bind( (double(*)(double))g, _1);    // 正确,但是相当丑陋
 1 void H(int a);
 2 //绑定全局函数
 3 auto f11 = std::bind(H, std::placeholders::_1);
 4 auto的类型实际上是std::function<void(int)>
 5
 6 //绑定带参数的成员函数
 7 std::function<void (char*, int)> f = std::bind(&ReadHandler::ConnectPreProcess, this, std::placeholders::_1, std::placeholders::_1);
 8
 9 //三元函数转换成一元函数
10 int f(int, char, double);
11 // 绑定f()函数调用的第二个和第三个参数,
12 // 返回一个新的函数对象为ff,它只带有一个int类型的参数
13 auto ff = bind(f, _1, ‘c’, 1.2);
14 int x = ff(7);

自己写代码示例如下:

int Func(int x, int y);
auto bf1 = std::bind(Func, 10, std::placeholders::_1);
bf1(20); ///< same as Func(10, 20)

int HelloWorld::AddFunc( int a, int b )
{return a + b;
}bool HelloWorld::init()
{auto bf2 = std::bind(&HelloWorld::AddFunc,this , std::placeholders::_1, std::placeholders::_2 );auto result1 = bf2(10, 20); ///< same as a.Func(10, 20)
std::function< int(int)> bf3 = std::bind(&HelloWorld::AddFunc, this, std::placeholders::_1, 100);auto result2 = bf3(10); ///< same as a.Func(10, 100)

}

上面的例子中,bf1是把一个两个参数普通函数的第一个参数绑定为10,生成了一个新的一个参数的可调用实体体; bf2是把一个类成员函数绑定了类对象,生成了一个像普通函数一样的新的可调用实体; bf3是把类成员函数绑定了类对象和第二个参数,生成了一个新的std::function对象。看懂了上面的例子,下面我们来说说使用bind需要注意的一些事项:

  • (1)bind预先绑定的参数需要传具体的变量或值进去,对于预先绑定的参数,是pass-by-value的
  • (2)对于不事先绑定的参数,需要传std::placeholders进去,从_1开始,依次递增。placeholder是pass-by-reference的
  • (3)bind的返回值是可调用实体,可以直接赋给std::function对象
  • (4)对于绑定的指针、引用类型的参数,使用者需要保证在可调用实体调用之前,这些参数是可用的
  • (5)类的this可以通过对象或者指针来绑定

std::function

它是函数、函数对象、函数指针、和成员函数的包装器,可以容纳任何类型的函数对象,函数指针,引用函数,成员函数的指针。
以统一的方式处理函数、函数对象、函数指针、和成员函数。允许保存和延迟执行函数。

  • 函数和成员函数作为function

function是一个拥有任何可以以"(...)"符号进行调用的值的类型。特别地,bind的返回结果可以赋值给function类型。function十分易于使用。(译注:更直观地,可以把function看成是一种表示函数的数据类型,就像函数对象一样。只不过普通的数据类型表示的是数据,function表示的是函数这个抽象概念。)例如:

 1 typedef std::function<float (int x, int y)> f ;// 构造一个函数对象,它能表示的是一个返回值为float,两个参数为int,int的函数
 2 struct int_div {        // 构造一个可以使用"()"进行调用的函数对象类型
 3     float operator() (int x, int y) const { return ((float)x)/y; };
 4 };
 5
 6 void HelloWorld::testing()
 7 {
 8     f f1= int_div();                    // 赋值
 9     auto result3 = f1( 10, 2);
10 }

成员函数可被看做是带有额外参数的自由函数:

 1 struct int_div {        // 构造一个可以使用"()"进行调用的函数对象类型
 2     float operator() (int x, int y) const { return ((float)x)/y; };
 3     int int_div_fun( int x ){ return x; };
 4 };
 5 typedef std::function<int (int_div*, int)> f_2;
 6
 7 bool HelloWorld::init()
 8 {
 9     f_2 f2 = std::mem_fn(&int_div::int_div_fun);            // 指向成员函数
10
11     int_div int_div_object;
12     int v = f2(&int_div_object, 5);  // 在对象x上用参数5调用X::foo()
13     std::function<int (int)> ff = std::bind( f2, &int_div_object, std::placeholders::_1);    // f的第一个参数是&x
14     v = ff(5);                // 调用x.foo(5)
15
16
17 }

ps:被vs2012的bug给坑了。因为看网上的代码于是刚开始第9行是这么写的:f_2 f2 = &int_div::int_div_fun;

然后就报错误:Error 1 error C2664: 'std::_Func_class<_Ret,_V0_t,_V1_t>::_Set' : cannot convert parameter 1 from '_Myimpl *' to 'std::_Func_base<_Rx,_V0_t,_V1_t> *'

查了一下,vs2010没有这个编译错误,但是2012有。2012必须得加上std::mem_fn才能编译。

  • 可以用function取代函数指针。因为它可以保存函数延迟执行,所以比较适合作为回调函数,也可以把它看做类似于c#中特殊的委托,只有一个成员的委托。
  •  1 struct int_div {        // 构造一个可以使用"()"进行调用的函数对象类型
     2     float operator() (int x, int y) const { return ((float)x)/y; };
     3     int int_div_fun( int x ){ return x; };
     4
     5     int_div( std::function<void()>& f ):m_callback(f){};
     6     void Notify()
     7     {
     8         m_callback();
     9     }
    10     std::function<void()> m_callback;
    11 };

  • function还可以作为函数入参,这样可以在函数外部控制函数的内部行为了,让我们的函数变得更加灵活。
  • void Foo(int x, std::function<void(int)>& f)
    {
    if(x%2==0)
    f(x);
    }void G(int x)
    {
    cout<<x<<endl;
    }void H(int x)
    {
    cout<<x+2<<endl;
    }void TestFoo()
    {
    auto f = std::bind(G, std::placeholders::_1);
    Foo(4, f);//在Foo函数外面更改f的行为
    f = std::bind(H, std::placeholders::_1);
    Foo(4, f);
    }

c++11中推出function是为了泛化函数对象,函数指针,引用函数,成员函数的指针,让我们可以按更统一的方式写出更加泛化的代码;推出bind是为了替换和增强之前标准库的bind1st和bind2st,让我们的用起来更方便!

c++11 std::bind与std::function相关推荐

  1. C++11 std::bind 和 std::placeholder

    @time 2019-07-07 @author Ruo_Xiao std::bind 则是用来绑定函数调用的参数的, 它解决的需求是我们有时候可能并不一定能够一次性获得调用某个函数的全部参数,通过这 ...

  2. C++11 std::bind std::function 高级用法

    C++11 std::bind std::function 高级用法 (c++11的新特性) 原文:https://blog.csdn.net/yangjie6898862/article/detai ...

  3. C++11 std::function, std::bind, std::ref, std::cref

    C++11 std::function, std::bind, std::ref, std::cref 转自:http://www.jellythink.com/ std::function 看看这段 ...

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

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

  5. C++11中std::bind的使用

    std::bind函数是用来绑定函数调用的某些参数的.std::bind它可以预先把指定可调用实体的某些参数绑定到已有的变量,产生一个新的可调用实体.它绑定的参数的个数不受限制,绑定的具体哪些参数也不 ...

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

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

  7. C++11新特性之std::bind()

    文章转载自:http://www.jellythink.com/archives/773 Cocos2d-x中有如下代码: // new callbacks based on C++11#define ...

  8. 函数对象,lamdda表达式,function函数包装,std::bind函数绑定

    一 函数对象 在学习其他知识之前,先来学习函数对象,然后引出std::lambda.std::function.std::bind等内容的学习,那么究竟什么是函数对象呢? 函数对象(Function ...

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

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

最新文章

  1. IBM超越谷歌抵达量子计算里程碑:研制出50量子位计算机
  2. ROS系统 动作编程
  3. 用Python实现冒泡排序
  4. python tkinter chk
  5. Android开发之引用framework.jar中的方法 | 引用framework.jar包
  6. java旋转图片后边上变黑_Java旋转图像将背景的一部分变成黑色
  7. three.js mtl材质贴图未显示_C4D材质到底该怎么用?大多数设计师都没搞明白!
  8. kafka集群搭建详细步骤
  9. Java面试-北大青鸟合肥科海学院
  10. 百战c++(数据库2)
  11. C#上位机控制51单片机LED灯开关
  12. Android推特图片保存路径,从twitter获取个人资料图片图像使用解析推特登录为Android...
  13. watermark-dom 添加水印使用方法
  14. 高博14讲--第三讲 三维空间刚体运动
  15. python实现天气查询
  16. 野性兽王 访著名魔兽大师4K^Grubby
  17. java 椭圆焦点 求是否在圆内_椭圆焦点位置的确定
  18. BUUCTF[GYCTF2020]Blacklist
  19. ios safari 开启无痕浏览(隐私模式)报QuotaExceededError: DOM Exception 22异常解决办法...
  20. Python爬取张家界风景美图

热门文章

  1. 非x面容解锁插件ios13_iOS13.5 Beta3 推送,戴口罩解锁更加方便
  2. opengl实现经纹理映射的旋转立方体_《图形编程技术学习》(五十三)环境映射...
  3. 导师推荐 | 第 4 期临床基因组家系分析,同时解决科研和临床问题
  4. NBT:你想成为计算生物学家?
  5. 复现Cell附图 |类器官的单细胞分析
  6. php 什么函数获取ip,在PHP中获取ip地址的方法有哪些
  7. Qt|Linux工作笔记-第二种方式读取Linux中top命令(直接读取,非重定向)
  8. Qt工作笔记-自定义开关控件
  9. html5和极速模式,浅谈360浏览器6.0版本极速模式与兼容模式_蓝戒的博客
  10. c语言打印删除空格,新人提问:如何将输出时每行最后一个空格删除