Boost bind使用方法

来源:互联网 发布:sql中union的用法 编辑:程序博客网 时间:2024/06/07 02:38

bind是C++98 标准库中函数适配器,bind1st和bind2nd的泛化和增强,可以适配任意的可调用对象,包括函数指针吗, 函数引用,成员函数,指针和函数对象。bind远远超过了STL中的函数绑定,最多可以绑定9个参数,并且对绑定对象要求很低,bind很好的增强了 标准库的功能,已经被收入C++0XTR1草案。

bind 位于boost命名空间

头文件: boost/bind.hpp

原理:bind 是一组重载的函数模板.
用来向一个函数(或函数对象)绑定某些参数. 
bind的返回值是一个函数对象,它内部保存f的拷贝,具有operator(),返回类型被自动推导为f的返回类型。发生调用时,这个函数对象将把之前存储的参数转发给f完成调用。

. bind接受的类型为:可以绑定 1.普通函数。2.成员函数。3.成员变量。4.函数对象。5.使用ref库。

bind的真正威力在于他的占位符,他们被分别定义为:_1,_2,_3 一直到_9,位于一个匿名命名空间。

eg:bind(func, _2, _1) (a1, a2); //函数调用发生时,接受真正的参数。 且占位符名字表示在调用式中的顺序,绑定表达式没有顺序要求。

它的源文件太长了.这里提供几个一般用法:

1、绑定普通函数

 void fun(int x, int y) {  cout << x << ", " << y << endl; }

现在我们看看怎么用bind 向其绑定参数. 
对于像 fun 这样的普通函数. 若fun 有n个参数. 则 bind 需要 n+1 个参数: 原始函数的地址 以及 n个要绑定的参数.

用法1: 
向原始函数 fun 绑定所有的参数

 boost::bind(&fun, 3, 4)     // bind的实参表依次为: 要绑定的函数的地址, 绑定到fun的第一个参数值, 第二个参数值...

这是最简单的绑定, bind表达式存储了fun和3, 4 的拷贝,产生一个临时函数对象。

// fun有多少个参数, 这里就要提供多少个.

表示将 3 和 4 作为参数绑定到 fun 函数. 
因为绑定了所有的参数. 现在我们调用bind所返回的函数对象:
 
boost::bind(&fun, 3, 4)( );  //无参数. 
就会输出 3, 4

用法2: 

向原始函数 fun 绑定一部分参数
 boost::bind(&fun, 3, _1)    // bind的实参表依次还是: 要绑定的函数的地址, 要绑定到fun的第一个参数值, 然后注意
        // 因为我们不打算向fun绑定第2个参数(即我们希望在调用返回的Functor时再指定这个参数的值)
        // 所以这里使用 _1 来占位. 这里的 _1 代表该新函数对象被调用时. 实参表的第1个参数.
        // 同理下边还会用到 _2 _3 这样的占位符. 不需要提前绑定的参数用占位符占位标识
这里只为fun绑定了第一个参数3. 所以在调用bind返回的函数对象时. 需要:
 boost::bind(&fun, 3, _1)(4);  //这个4 会代替 _1 占位符.
输出 3, 4
同理 boost::bind(&fun, _1, 3)(4); 
输出 4, 3

用法3:
不向 fun 绑定任何参数
 boost::bind(&fun, _1, _2)   // _1 _2 都是占位符. 上边已经说过了.
所以它就是 将新函数对象在调用时的实参表的第1个参数和第2个参数 绑定到fun函数.  
 
boost::bind(&fun, _1, _2)(3, 4);    // 3将代替_1占位符, 4将代替_2占位符.
输出 3, 4
同理 boost::bind(&fun, _2, _1)(3, 4);   // 3将代替_1占位符, 4将代替_2占位符.
会输出 4, 3  
同理 boost::bind(&fun, _1, _1)(3);     // 3将代替_1占位符
会输出 3, 3

对于普通函数就这些. 对于函数对象. 如:
 struct Func 

{

  void operator()(int x)  {   cout << x << endl;  }

 } f;
绑定的时候可能要指出返回值的类型:
 boost::bind<void>(f, 3)();  //指出返回值的类型 void

eg: 看下面一些例子

      int f(int a, int b) { return b + a; };
      int g(int a, int b, int c) { return a + b * c; };
      typedef int(*f_type) (int, int);     //函数指针
      typedef int(*g_type) (int, int, int);

      

      //绑定普通函数
     std::cout << bind(f, 1, 2) << std::endl;   //相当于 f(1, 2);
     std::cout << bind(g, 1, 2, 3) << std::endl; 

 
     f_type pf = f;
     g_type pg = g;
     int x = 1, y = 2, z = 3;
     std::cout << bind(pf, _1, 9)(x) << std::endl;   //(*pf)(x, 9)
     std::cout << bind(pg, _3, _2, _2)(x,y,z) << std::endl;   //(*pg)(z, y, y)

 2 、绑定非静态成员函数  

由于成员函数指针不能直接调用operator(),它必须被绑定到一个对象或者指针,然后才能得到this指针进而调用成员函数。因此bind需要牺牲一个占位符的位置,要求用户提供一个类的实例,引用或指针,通过对象作为第一个参数来调用成员函数,即:

bind(&X::func, x, _1, _2, ...);  这时意味着最多只能绑定8个参数

 struct A 

{
     void func(int x, int y) 

     {
           cout << x << "," << y << endl;
     }
 };

 A a, &然= a;
 A* pa = new A; //指针
 boost::shared_ptr<A> ptr_a(pa);  //智能指针.

现在要向像 A::func 这样的非静态成员函数绑定. 
若A::func有n个参数, 则 bind 要有 n+2 个参数: 指向成员函数fun的指针, 绑定到this的对象, n个参数.
如:  
 boost::bind(&A::func, a, 3, 4)();    //输出 3, 4

 boost::bind(&A::func, ra, 3, 4)();   //输出 3, 4   //引用
 boost::bind(&A::func, pa, 3, 4)();   //输出 3, 4
 boost::bind(&A::func, ptr_a, 3, 4)();//输出 3, 4

也可以用boost::bind(&A::func, this, 3, 4)();    //输出 3, 4 形式
同样可以用 _1 这样的占位符. 如:
 boost::bind(&A::func, _1, 3, 4)(ptr_a);//输出 3, 4

可以看出. 不论传递给bind 的第2个参数是 对象. 对象指针. 还是智能指针. bind函数都能够正常工作.

同样,bind支持绑定虚成员函数,用法和成员函数相同。

3、绑定成员变量

bind可以绑定public成员变量,就像一个选择器,用法与绑定成员函数类似,只需把成员变量名像一个成员函数一样去使用。

struct point
{
    int x, y;
    point(int a = 0, int b = 0) : x(a), y(b){}
    void print() { std::cout << x << y << std::endl; };
};

vector<point> v(10);

vector<int> v2(10);

transform(v.begin(), v.end(), v2.begin(),bind(&point::x, _1));

4、绑定函数对象

bind可以绑定任意的函数对象(仿函数),包括标准库所有预定义的函数对象。

注意的是:如果函数对象内部定义了返回值类型,则bind可以自动推导出返回值类型,用法和绑定普通函数一样, 如果没有定义,则在绑定形式上做改变,就像这样boost::bind<void>(f, 3)(); //需要指出返回值的类型 void

标准库和boost库中的大部分函数对象都具有返回值类型的定义,可以直接使用,自定义函数对象指定即可。

bind(std::greater<int>(), _1, 10);  //检查x > 10

5、使用ref库

bind采用拷贝的方式绑定对象和参数, 因此bind库可以搭配ref库使用, ref库包装了对象的引用,可以让bind存储对象引用的拷贝,从而降低拷贝代价

eg:   int x = 10;

bind(g, _1, cref(x), ref(x))(10);

f af;   //一个函数对象,

bind<int>(ref(af), _1, _2)(10, 20);


6、bind 高级用法

bind嵌套绑定

如果我们有f(x), g(x)两个函数,那么f(g(x))的bind表达式就是:

bind(f, bind(g, _1))(x);