天天看點

boost bind使用指南

bind - boost

頭檔案: boost/bind.hpp

bind 是一組重載的函數模闆.

用來向一個函數(或函數對象)綁定某些參數.

bind的傳回值是一個函數對象.

它的源檔案太長了. 看不下去. 這裡隻記下它的用法:

9.1 對于普通函數

假如有函數 fun() 如下:

 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的第一個參數值, 第二個參數值...

        // 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

9.2 對于非靜态成員函數

假如有:

 struct A {

  void func(int x, int y) {

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

  }

 };

 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, pa, 3, 4)();   //輸出 3, 4

 boost::bind(&A::func, ptr_a, 3, 4)();//輸出 3, 4

同樣可以用 _1 這樣的占位符. 如:

 boost::bind(&A::func, _1, 3, 4)(ptr_a);//輸出 3, 4

可以看出. 不論傳遞給bind 的第2個參數是 對象. 對象指針. 還是智能指針. bind函數都能夠正常工作.

9.3 bind嵌套

有個類如下. 記錄人的資訊:

 class Personal_info {

  string name_;

  int age_;

 public:

  int get_age();

  string name();

 };

 vector<Personal_info> vec;

 ...

現在要對 vec 排序. 可以用 bind 函數做一個比較謂詞

 std::sort( 

  vec.begin(), 

  vec.end(), 

  boost::bind(

   std::less<int>(),   

   boost::bind(&personal_info::age,_1),     //_1 占位符是 sort 中調用比較函數時的第一個參數.

   boost::bind(&personal_info::age,_2)));   //_2 占位符是 sort 中調用比較函數時的第二個參數.

9.4 函數組合

假如有:

 vector<int> ints;

 ...

想用 std::count_if() 來求ints中有多少是 >5 且 <=10 的. 這在正常代碼中通常就要寫一個函數來實作這個謂詞:

 if (i>5 && i<=10) ...

現在用bind則可以:

 std::count_if( 

  ints.begin(),  ints.end(), 

  boost::bind(   

   std::logical_and<bool>(),   

   boost::bind(std::greater<int>(),_1,5),   

   boost::bind(std::less_equal<int>(),_1,10)));

9.5 綁定到成員變量

有:

 map<int, string> my_map;

 my_map[0]="Boost";my_map[1]="Bind";

現在要輸出所有元素的 second 成員. 也就是輸出這些字元串. 其中的列印函數如下:

 void print_string(const string& s) { 

  std::cout << s << '/n';

 }

則可以:

 for_each( 

  my_map.begin(), 

  my_map.end(), 

  boost::bind(

   &print_string,

   boost::bind(&std::map<int,std::string>::value_type::second,_1)

   )

  );

汗... 看不懂bind的源碼. 也不知是如何實作這些功能的. 隻能等<<boost源碼剖析>>出來了.

 注意:

(以下補于08年6月3日)

boost::bind() 傳回的函數對象會儲存要綁定的實參. 而且總是拷貝一份以值的方式儲存..

這主要是考慮到被綁定的實參的生命期.  

但這并不總是我們期望的. 例如有時我們希望它儲存指針或引用:

有函數:

void f(int & x) { ++x; }

然後:

int n = 0;

bind(&f, n)();    //我們希望 n==1 . 但實際上沒有這樣...

要避免這種對象複制.  而

要bind得到的函數對象儲存實參的引用語義. 可以:

使用 boost::ref()  或 boost::cref() 如

bind(&f, ref(n))();        //OK,  執行後 n==1

如果是綁定一個對象到它的成員函數上. 如:

A a;

bind(&A::fun, a);       //則儲存的是 a對象的拷貝.

要避免這種拷貝. 除了上面提到的 ref() 外, 也可以:

bind(&A::fun, &a);      //用指針.  反正用對象和用指針都可以. 而用指針可以避免對象拷貝的問題. 

注意: (以下補于6月10日)

bind () 的第一個參數——被綁定函數——是不被求值的. 如下例:

typedef void (*pf)(int);

std::vector<pf> v;  //v中有一些函數指針.

std::for_each(v.begin(), v.end(), bind(_1, 5));

//想實作 _1(5);  這樣的調用. 但這樣不行!

正确的做法是借助 boost::apply  

apply也是一個函數對象. 它的作用如下:

apply<void> a;   //模闆參數為函數對象的傳回值類型.

a(x);       //相當于調用 x();

a(x, y);    //相當于調用  x(y);