1. 程式人生 > >第11課 std::bind和std::function(2)_std::bind綁定器

第11課 std::bind和std::function(2)_std::bind綁定器

pan std name iostream emf end cnblogs left eid

1. 溫故知新:std::bind1st和std::bind2nd

(1)bind1st、bind2nd首先它們都是函數模板,用於將參數綁定到可調用對象(如函數、仿函數等)的第1個或第2個參數上

(2)函數的返回值是一個函數對象。它用於包裝和改造傳入的函數(或仿函數),並形成一個新的仿函數對象(是一個可調用對象

(3)與舊的可調用對象相比,新的仿函數對象參數個數少了1個。(相當於給少掉的那個參數一個默認的值

2. std::bind綁定器

(1)首先,std::bind也是一個函數模板返回值是一個仿函數,也是可調用對象。它的作用與bind1st和bind2st類似,是這兩個函數的加強版。但極大地提高了靈活性,可以完全替代bind1st和bind2nd。

(2)bind的作用主要就是將可調用對象變成std::function對象(即仿函數對象),主要體現在兩個方面。

  ①將多元的可調用對象與其參數一起綁定成一個仿函數對象。

  ②將多元(設參數個數為n)的可調用對象轉成一元或(n-1)元的可調用對象,即只綁定部分參數

(3)std::bind可以綁定的對象(註意bind的返回值是仿函數)

  ①普通函數(functions);

  ②函數對象(仿函數,function objects);

  ③類的成員函數(member functions。註意:_1必須是某個對象的地址

  ④類的數據成員(data members註意:_1必須是某個對象的地址

【編程實驗】std::bind初探

#include <iostream>
#include <vector>
#include <functional>  // for std::bind
#include <typeinfo>

using namespace std::placeholders;  //讓_1, _2, _3,...可見!
using namespace std;

//除法函數:x/y
double my_divide(double x, double y)
{
    return x / y;
}

struct MyPair
{
    
double a, b; MyPair(int a, int b):a(a), b(b) { cout << "MyPair(int a, int b)" << endl; } //註意成員函數的第1個參數是this!!! double mutiply(){return a * b;} }; int main() { //1、綁定函數 auto fn1 = bind(my_divide, 10, 2); //返回一個std::function類型的仿函數 //function<double(void)> fn1 = bind(my_divide, 10, 2); //綁定完,fn1是無參,所以為void //cout << typeid(fn1).name() << endl; cout << fn1() << endl; auto fn2 = bind(my_divide, _1, 2); //my_divide的第2個參數綁定為2 cout << fn2(10) << endl; // 輸出5 //cout << fn2(10, 3) << endl; // 輸出仍然為5! auto fn3 = bind(my_divide, _2, _1); cout << fn3(10, 2) << endl; //輸出:0.2。註意10為第1個參數,被綁到_1的位置,2綁到_2的位置 auto fn4 = bind<int>(my_divide, _1, _2); //指定返回值為int型 cout << fn4(10, 3) << endl; //2、綁定類的成員 MyPair mp{10, 2}; //註意,mp是個聚合對象,可用{}直接初始化(雖無2個參數的構造函數)。 auto ftor_memfn = bind(&MyPair::mutiply, _1); //成員函數,其實有個this指針,須放入_1 cout << ftor_memfn(mp) << endl; //20,傳入mp對象的地址(這裏傳的是引用) auto ftor_memdata = bind(&MyPair::a, mp); //傳mp對象的副本, //auto ftor_memdata = bind(&MyPair::a, &mp); //傳mp的地址 cout << ftor_memdata() << endl; //10 ftor_memdata() = 100; //mp副本的a值被改為100 cout << mp.a << endl; //10,mp本身的a值未被改變,仍為10 cout << ftor_memdata() << endl; auto ftor_memdata2 = bind(&MyPair::b, _1); cout << ftor_memdata2(mp) << endl; //2 ftor_memdata2(mp) = 50; //傳mp的引用 cout << mp.b << endl; //由於按引用傳遞,b的值被改! cout << ftor_memdata2(mp) << endl; return 0; }

3. 使用std::bind的註意事項

(1)bind預先綁定的參數需要傳具體的變量或值進去,對於預先綁定的參數是按值傳遞的

(2)對於不事先綁定的參數,需要傳std::placeholders進去,從_1開始,依次遞增。註意,對於placeholder是按引用傳遞的

(3)通過placeholder可以改變傳參的順序。同時如果放置了placeholder_x的占位符,當調用時就必須給足至少x個實參

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

(5)對於綁定的指針、引用類型的參數,使用者需要保證在可調用對象調用之前,這些參數是可用的。

【編程實驗】placeholder、組合使用bind函數

#include <iostream>
#include <vector>
#include <algorithm>   //for count_if
#include <functional>  // for std::bind

using namespace std;
using namespace std::placeholders;

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

int main()
{
    auto out1 = bind(output, _1, 2);
    out1(1);  //輸出:1, 2
    
    auto out2 = bind(output, 2, _1);
    out2(1);  //輸出:2, 1
    
    auto out3 = bind(output, 2, _2);
    out3(1, 3); //輸出2, 3(註意,第1個參數被默認的2取代了)
    //out3(1);  //error, 調用時需給出第2個參數
    
    auto out4 = bind(output, 2, _2);
    out4(1, 3); //輸出2, 3
    //out4(1);  //error, 調用時需給出第2個參數
    
    auto out5 = bind(output, _2, _1);
    out5(1, 3); //輸出3, 1(第1個實參對應_1,第2個實參對應_2)
    
    vector<int> v{15, 37, 94, 50, 73, 58, 28, 98};
    
    //通過bind2nd綁定
    int n = count_if(v.begin(), v.end(), not1(bind2nd(less<int>(), 50)));
    cout <<"n = " << n << endl; //5(大於等於50的元素個數)
    
    //通過bind綁定
    auto fn = bind(less<int>(), _1, 50);
    cout << count_if(v.begin(), v.end(), fn) << endl; //3,小於50的元素個數
    cout << count_if(v.begin(), v.end(), bind(less<int>(), _1, 50)) << endl; //3
    
    //組合使用bind
    //查找(50,73]之間的元素個數
    auto f = bind(logical_and<bool>(), bind(greater<int>(), _1, 50), bind(less_equal<int>(), _1, 73));
    cout << count_if(v.begin(), v.end(), f) << endl; //2
    
    return 0;
}

第11課 std::bind和std::function(2)_std::bind綁定器