boost::function

来源:互联网 发布:免费虚拟主机空间php 编辑:程序博客网 时间:2024/05/01 17:46

function的概念

  function是一个函数对象的“容器”,概念上像是c/c++中函数指针类型的泛化,是一种“只能函数指针”。它以对象的形式封装了原始的函数指针或函数对象,能够容纳任意符合函数签名的可调用对象。因此它可以被用于回调机制,暂时保管函数或函数对象,在之后需要的时机再调用。
  function可以配合bind/lambda使用,存储bind/lambda表达式的结果,使其可以被多次调用。

function的声明

  function只需要一个模板参数,这个参数就是将要容纳的函数类型,例如
  

    function<int()> func;

将声明一个可以容纳返回值为int,无参数的function对象。
  这种声明很容易理解,在尖括号中的类型声明就像一个没有函数名的函数原型
  function的函数声明也可以像真的函数声明那样带有参数名。例如:
  

    function<int (int a,int b,int c)> func2;

    function<int (int,int,int)> func2;

是完全等价的。

用法

  function的构造函数可以接受任意符合模板中声明的函数类型的可调用对象,例如函数指针和函数对象,或者是另一个function对象的引用。
  无参数的构造函数或传入空指针构造将创建一个空的function对象,不持有任何可调用物。调用空的function对象将抛出bad_function_call异常,因此在使用function前好检测其有效性(empty(),operator!)。
  

  示范function 基本用法的代码如下:

#include <boost/function.hpp>using namspace boost;int f(int a,int b){    return a+b;}int main(){    function<int(int, int)> func;  //无参数构造function对象    assert(!func);    func = f;    assert(func.contains(&f));    if(func)    {        cout<<func(10,20);    }    func = 0;    assert(func.empty());}

  只要函数签名式一致,function也可以存储成员函数和函数对象,或者是bind/lambda表达式。假设我们有如下的一个类demo_class,它既有普通成员函数,又重载了operator():

struct demo_class{    int add(int a,int b)    {        return a+b;    }    int operator()(int x) const    {        return x*x;    }};

  存储成员函数时,可以直接在function声明的函数签名式中指定类的类型,然后用bind绑定成员函数:

    function<int(demo_class&,int,int)> func1;    func1 = bind(&demo_class::add,_1,_2,_3);    demo_class sc;    cout<<func1(sc,10,20);

  我们也可以在函数类型中仅写出成员函数的签名,在bind时直接绑定类的实例:

    function<int(int,int)> func2;    func2 = bind(&demo_class::add,&sc,_1,_2);    cout<<func2(10,20);

用于回调
  function可以容纳任意符合函数签名式的可调用物,因此它非常适合代替函数指针,存储用于回调的函数。
  作为示范,我们定义一个demo_class类,它使用function代替函数指针作为内部类型保存回调函数,存储形式为void(int)的可调用物。

class demo_class{private:    typedef function<void(int)> func_t;    func_t func;    int n;publicL:    demo_class(int i)    :n(i)    {}    /*    使用模板函数accept()接受回调函数。之所以使用模板函数,是因为这种形式更加灵活,用户可以在不关心也不知道内部存储形式的情况下,传递任何可调用对象,包括函数指针和函数对象。    */    template<typename CallBack>    void accept(CallBack f)    {        func = f;    }    //成员函数run()用于回调函数    void run()    {        func(n);    }};

  接下来我们定义一个用于回调的函数,它将输入翻番:

void call_back_func(int i){    cout<<"call_back_func:";    cout<<i*2<<endl;}

  demo_class的回调可以这样使用:

int main(){    demo_class dc(10);    dc.accept(call_back_func);    dc.run();}

  function可以搭配bind,把bind表达式作为回调函数,可以接受类成员函数,或者把不符合函数签名式的函数bind转为可接受的形式。下面定义一个回掉函数工厂类,它有两个回掉函数:
  

class call_back_factory{public:    void call_back_func1(int i)    {        cout<<"call_back_factory1:";        cout<<i*2<<endl;    }    void call_back_func2(int i,int j)    {        cout<<"call_back_factory2:";        cout<<i*j*2<<endl;    }}

  function搭配bind的用法如下:
  

int main(){    demo_class dc(10);    call_back_factory cbf;    dc.accept(bind(&call_back_factory::call_back_func1,cbf,_1));    dc.run();    dc.accept(bind(&call_back_factory::call_back_func2,cbf,_1,5));    dc.run();}

  通过以上代码可以看到,function无需改变回调的接口就可以解耦客户代码,使客户代码不必绑死在一种回调形式上。

0 0