boost:bind使用指南

 

bind - boost數組

頭文件: boost/bind.hppapp

bind 是一組重載的函數模板.
用來向一個函數(或函數對象)綁定 某些參數.
bind的返回值是一個函數對象.less

它的源文件太長了. 看不下去. 這裏只記下它的用法:函數

9.1 對於普通函數this

假若有函數 fun() 以下:
 void fun(int x, int y) {
  cout << x << ", " << y << endl;
 }
如今咱們看看怎麼用 bind 向其綁定參數.
對於像 fun 這樣的普通函數. 若fun 有n個參數. 則 bind 須要 n+1 個參數: 原始函數的地址 以及 n個要綁定的參數.spa

第 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 模板(來自boost/bind/apply.hpp).  
apply也是一個函數對象. 它的做用以下:
apply<void> a;   //模板參數爲函數對象的返回值類型.
a(x);       //至關於調用 x();
a(x, y);    //至關於調用  x(y);
a(x, y, z);  //至關於調用 x(y, z);
因此錯誤的bind應該寫爲:
std::for_each(v.begin(), v.end(), bind(apply<void>(), _1, 5));

相關文章
相關標籤/搜索