C++11 學習筆記 std::function和bind綁定器


C++11 學習筆記 std::function和bind綁定器

一.std::function

      C++中的可調用對象雖然具有比較統一操作形式(除了類成員指針之外,都是后面加括號進行調用),但定義方法五花八門。為了統一泛化函數對象,函數指針,引用函數,成員函數的指針的各種操作,讓我們可以按更統一的方式寫出更加泛化的代碼,C++11推出了std::function。

  std::function是可調用對象的包裝器。它是一個類模板,可以容納除了類成員(函數)指針之外的所有可調用對象。通過指定它的模板參數,它可以用統一的方式處理函數,函數對象,函數指針,並允許保存和延遲執行它們。

#1include <iostream>
 #include <functional>
 
 using namespace std;
 
 void func(void){
     cout << __FUNCTION__ << "(" << a << ") ->: ";
 }
 
 class Foo
 {
 public:
     static int foo_func(int a){
         cout << __FUNCTION__ << "(" << a << ") ->: ";
         return a;
     }
 };
 
 class bar
 {
 public:
     int operator()(int a){
         cout << __FUNCTION << "(" << a << ") ->: ";
         return a;
     }
 };
 
 int main(){
     //綁定一個普通函數
     std::function<void(void)> fry = func;
     fr1();
 
     
     //綁定一個類的靜態成員函數
     std::function<int(int)> fr2 = Foo::foo_func;
     cout << fr2(123) << endl;
     
     //綁定一個仿函數
     Bar bar;
     fr2 = bar;
     cout << fr2(123) <<endl;
 
     return 0;
 }

std::function的使用方法:我們給std::function填入合適的函數簽名(即一個函數類型,只需要包括返回值和參數表)之后,它就變成了一個可以容納所有這一類調用方式的“函數包裝器”。

 

 #include <iostream>
 #include <functional>
 
 using namespace std;
 
 class A
 {
 public:
     A(const std::function<void()>& f){
         :callback_(f){}
     
     void notify(void){
         callback_();
     }
 private:
     std::function<void()> callback_;
 };
 
 class Foo
 {
 public:
     void operator()(void){
         cout << __FUNCTION__<< endl;
     }
 };
 
 int main(){
     Foo foo;
     A aa(foo);
     aa.notify();
     
     return 0;
 }

從上面的例子看,std::function可以取代函數指針的作用。因為它可以保存函數延遲執行,所以比較適合作為回調函數,也可以把它看做類似於C#中特殊的委托(只有一個成員的委托)。

 #include <iostream>
 #include <functional>
 
 using namespace std;
 
 void call_when_even(int x, const std::function<void(int)>& f){
     if(!(x & 1)){
         f(x);
     }
 }
 
 void output(int x){
     cout << x <<" ";
 }
 
 int main(void){
     for(int i=0;i<10;i++){    
         call_when_even(i, output);
     }
     cout<<endl;
 
     return 0;
 }

std::function還可以作為函數入參,這樣可以在函數外部控制函數的內部行為了,讓我們的函數變得更加靈活。
 

二.std::bind綁定器

  std::bind用來將可調用對象與其參數一起進行綁定。綁定后的結果可以使用std::function進行保存,並延遲調用到任何我們需要的時候。通俗來講,它主要有兩大作用:

  1).將可調用對象與其參數一起綁定成一個仿函數。

  2).將多元(參數個數為n,n>1)可調用對象轉成一元或者(n-1)元可調用對象,即只綁定部分參數。

  function模板類和bind模板函數,都可以實現類似函數指針的功能,但卻卻比函數指針更加靈活,特別是函數指向類的非靜態成員函數時。

  1).std::function可以綁定到全局函數/類靜態成員函數(類靜態成員函數與全局函數沒有區別)。

  2).綁定到類的非靜態成員函數,則需要使用std::bind。

 #include <iostream>
 #include <functional>
 
 using namespace std;
 
 void call_when_even(int x, const std::function<void(int)>& f){
     if(!(x & 1)){
         f(x);
     }
 }
 
 void output(int x){
     cout << x << " ";
 }
 
 void output_add_2(int x){
     cout << x +2 << " ";
 }
 
 int main(){
     {
         auto fr = std::bind(output, std::placeholders::_1);
         for(int i=0;i<10;i++){
            call_when_even(i, fr);
         }
         cout << endl;
     }
     
     {
         auto fr = std::bind(output_add_2, std::placeholders::_1);
         for(int i=0;i<10;i++){
             call_when_even(i, fr);
         }
         cout << endl;
     }
 
     return 0;
 }

"std::placeholders::_1"是一個占位符對象,用於表示當函數output(output_add_2)通過函數fr進行調用時,函數fr的第一個參數在函數output(output_add_2)的參數列表中的位置。

下面是兩個樣例:

 

 #include <iostream>
 #include <functional>
 
 using namespace std;
 
 class A
 {
 public:
     int i_=0;
 
     void output(int x, int y){
         cout << x << " " << y <<endl;
     }
 };
 
 int main(){
     A a;
     std::function<void(int, int)> fr = std::bind(&A::output, &a, std::placeholders::_1,std::placeholders::_2);
     fr(1,2);
 
     std::function<int&(void)> fr_i = std::bind(&A::i_, &a);
     fr_i() = 123;
     cout << a.i_ << endl;
 
     return 0;
 }

 

 //使用組合bind函數,找出集合中大於5小於10的元素個數
 #include <iostream>
 #include <functional>
 
 using namespace std;
 
 auto f = std::bind(std::logical_and<bool>(),std::bind(std::greater<int>(),_1,5),std::bind(std::less_equal<int>(),  _1, 10));
 
 int main(){
      set<int> se={1,2,3,4,5,6,7,8,9};
     int count = std::count_if(se.begin(), se.end(), f);
     cout << count <<endl;
     
     return 0;
 }

std::bind需要注意的一些事項:(http://www.cnblogs.com/slysky/p/3822640.html)

1).std::bind預先綁定的參數需要傳具體的變量或值進去,對於預先綁定的參數,是pass-by-value的

2).對於不事先綁定的參數,需要傳std::placeholders進去,從_1開始,依次遞增。placeholder是pass-by-reference的

3).bind的返回值是可調用實體,可以直接賦給std::function對象

4).對於綁定的指針、引用類型的參數,使用者需要保證在可調用實體調用之前,這些參數是可用的

5).類的this可以通過對象或者指針來綁定


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM