boost::function

来源:互联网 发布:debian 软件源配置 编辑:程序博客网 时间:2024/05/01 20:02

原文地址 :http://blog.csdn.net/fengbangyue/article/details/7185340

function是一个函数对象的“容器”,概念上像是C/C++中函数指针类型的泛化,是一种“智能函数指针”。它以对象的形式封装了原始的函数指针或函数对象,能够容纳任意符合函数签名的可调用对象。因此,它可以被用于回调机制,暂时保管函数或函数对象,在之后需要的时机在调用,使回调机制拥有更多弹性。

   说道回调,以前在没有使用虚函数,即没有学习boost的function时,我认识的回调就是C语言中的typedef 返回类型  (*pointer)(参数列表);当时也一直在想,C++不是面向对象吗?怎么还一直存在typedef 定义的这种回调函数,就没有一种替代方法吗?现在是否一切都不是不可替换的了。

  function可以配合bind使用,存储bind表达式的结果,使bind可以被多次调用,因为我们知道bind返回一个函数对象嘛?而且我们也可以尝尝看到他们是经常被搭配在起使用的。

  那如何使用function,和bind差不多,function位于命名空间boost,为了使用function组件,需要包含头文件<boost/function.hpp>,即:

     #include<boost/function.hpp>

     using namespace boost;


    现在主要是考虑如何使用function,因此其如何实现我们基本不去关心,直接看如何使用就OK了,function是一个模板类,因此在使用的时候需要指定函数原型如何,例如:

function<int()> func;表示func可以接受 返回类型为Int,函数无参数的函数的地址。这样真是一目了然啊。但书上也说了,有些老的编译器并不支持这种写法,要写成下面这样:

funcion<int> func,如果有一个参数就是funcion<int,int> func,这两个Int中,前面一个表示返回值,第二个表示参数,太不直观了,严重坚持第一种写法,让老编译器见鬼去吧!


  function的构造函数可以接受任意符合模板中声明的函数类型的可调用对象,如函数指针和函数对象,也可以是另一个function对象的引用,之后在内部存储一份它的拷贝。无参或空指针将构造一个空function对象,不持有任何可调用物,调用空的function对象将抛出bad_function_call异常,因此在使用function前最好检查一下它的有效性。可以用empty()测试function是否为空,或者用重载操作符operator!=来测试。function对象也可以再bool上下文中直接测试它是否为空,它是类型安全的。

   function的其他成员函数如clear()可以直接将function对象置空,它与使用operator=的效果一样。function模板成员函数target可以返回function对象内部持有的可调用物Functor的指针,如果function为空则返回NULL。而contain()函数可以检测function是否持有一个Functor对象。最后,function提供了operator(),它把传入参数转交给内部保存的可调用物,完成真正的函数调用。

  function重载了operator==和operator!=,可以用来与被包装的函数或函数对象进行比较。如果存储的是函数指针,那么比较相当于

function.target<Functor>() == func_pointer

例如:

function<int(int,int)> func(f);

assert(func == f);如果function存储的是函数对象,那么要求函数对象必须重载operator==。

而两个function对象不能使用==和!=直接比较,这是特意的。因为function存在到bool的隐式转换,function定义了两个function对象的operator==但没有实现,企图比较两个function对象会导致编译错误,此处要问,为什么不提供比较呢,我目前还没有想到提供两个比较的意义何在,因此应该是没有这个必要吧。


在function中可以使用ref、cref库来降低function参数的拷贝工作。function不要求ref库提供operator(),因为它能够自动识别包装类referrence_wrapper<T>,并调用get()方法获得被包装的对象,见代码片段。


将function用于回调,可以说是一个强大的功能之处。在书上还列举了使用对象函数作为回调函数,用来实现带状态的回调。另外由于bind函数存在,甚至在我们使用回调函数时把不符合function要求的函数签名的函数通过bind函数来进行转换(主要是参数个数不一致的情况),而不需要改动回调接口。学习代码如下:

[cpp] view plain copy
  1. #include <boost/function.hpp>  
  2. #include <boost/bind.hpp>  
  3. using namespace boost;  
  4.   
  5. int f(int a, int b)  
  6. {  
  7.     return a + b;  
  8. }  
  9.   
  10. struct demo_class  
  11. {  
  12.     int add(int a,int b)  
  13.     {  
  14.         return a + b;  
  15.     }  
  16.   
  17.     int operator()(int x)const  
  18.     {  
  19.         return x * x;  
  20.     }  
  21. private:  
  22.     typedef function<void(int)> func_t;//function类型定义  
  23.     func_t func;  
  24.   
  25.     int n;//内部成员变量  
  26. public:  
  27.     demo_class(){};  
  28.     demo_class(int i):n(i){};  
  29.   
  30.     template<typename CallBack>  
  31.     void accept(CallBack f)  
  32.     {  
  33.         func = f;  
  34.     }  
  35.   
  36.     void run()  
  37.     {  
  38.         func(n);  
  39.     }  
  40. };  
  41.   
  42. void call_back_func(int i)  
  43. {  
  44.     cout<<"call back func:";  
  45.     cout<<i * 2<<endl;  
  46. }  
  47.   
  48. int Test_Function()  
  49. {  
  50.     function<int(int,int)> func;//无参构造function对象  
  51.     assert(!func);//此时不持有任何对象  
  52.   
  53.     func = f;//func存储了f对象  
  54.     if (func)//可以转换为bool值  
  55.     {  
  56.         cout<<func(10,20)<<endl;//调用function的operator()函数,并通过其将参数传给其持有的对象f  
  57.     }  
  58.   
  59.     func = 0;//将function对象清空,相当于clear函数  
  60.     assert(func.empty());//使用empty()函数判断是否为空  
  61.   
  62.     function<int(demo_class&,int,int)> func1;//用来存储成员函数时可以直接在function声明的函数签名中指定类的类型,然后用bind绑定成员函数,此处成员函数的返回类型没有指定啊?  
  63.     func1 = bind(&demo_class::add,_1,_2,_3);//需要绑定三个参数,一个是对象,另一个函数参数  
  64.     demo_class sc;  
  65.     cout<<func1(sc,20,20)<<endl;//调用类的成员函数  
  66.   
  67.     //下面的方法直观点,保持和普通函数调用方法一致  
  68.     function<int(int,int)> func2;//无参构造function对象  
  69.     func2 = bind(&demo_class::add,&sc,_1,_2);//比普通函数多了一个类对象地址  
  70.     cout<<func2(30,20)<<endl;//调用成员函数  
  71.   
  72.     function<int(int)> func3;  
  73.     func3 = cref(sc);//使用cref包装常对象的引用,参看demo_class::operator(int x)const  
  74.     cout<<func3(10)<<endl;  
  75.   
  76.     //用于回调时  
  77.     demo_class dc(20);  
  78.     dc.accept(call_back_func);//接受回调函数  
  79.     dc.run();  
  80.     return 0;  
  81. }  


0 0
原创粉丝点击