詳解C++11中綁定器bind的原理與使用
bind1st和bind2nd什么時候會用到
bind用于綁定可調用 (Callable) 對象(函數對象、指向函數指針、到函數引用、指向成員函數指針或指向數據成員指針)和其參數。返回值為綁定成功后的函數對象
C++11中引入的function機制,其中綁定器主要有三種:bind1st、bind2nd、bind(C++11)
函數對象
盡管函數指針被廣泛用于實現函數回調,但C++還提供了一個重要的實現回調函數的方法,那就是函數對象。函數對象(也稱“函數符”)是重載了“()”操作符的普通類對象。因此從語法上講,函數對象與普通的函數行為類似。
用函數對象代替函數指針有幾個優(yōu)點:
首先,因為對象可以在內部修改而不用改動外部接口,因此設計更靈活,更富有彈性。函數對象也具備有存儲先前調用結果的數據成員。在使用普通函數時需要將先前調用的結果存儲在全程或者本地靜態(tài)變量中,但是全程或者本地靜態(tài)變量有某些我們不愿意看到的缺陷。
其次,在函數對象中編譯器能實現內聯調用,從而更進一步增強了性能。這在函數指針中幾乎是不可能實現的。
C++11還提供了limbda表達式來實現函數的靈活調用。詳見《C++ Primer Plus》第18章
函數對象實際上是類調用operator()()小括號運算符重載,實現像在“調用函數”一樣的效果,因此還有個別名叫“仿函數”。函數對象示例代碼如下:
class Print {
public:
void operator()(string &s) { cout << s << endl; }
};
int main() {
string s = "hello world!";
Print print; //定義了一個函數對象print
print(s);
return 0;
}
上面代碼print(s);語句,看似像函數調用,其實是類對象print調用其小括號運算符重載print.operator(string &s)。print就是一個函數對象,至此對函數對象就有了基本的認識
為什么需要綁定器?在使用STL時經常會遇到STL算法中需要傳遞某元函數對象,比如在寫sort時,第三個參數決定了我們的排序規(guī)則,用來接收一個“比較器”函數對象,該函數對象是一個二元的匿名函數對象,形如greator()或者less()。二元函數對象的意思是,這個函數對象的小括號運算符重載函數接收兩個參數,那么幾元就表示接收幾個參數。
我們知道系統自帶的greater()和less()模板類對象是二元匿名函數對象,但是像泛型算法find_if第三個參數接收一元函數對象,所以需要通過綁定器將其轉換為一元函數對象,可以通過bind1st和bind2nd去綁定,顧名思義,前者對二元函數對象的第一個參數進行綁定,后者對二元函數對象的第二個參數進行綁定,兩個綁定器均返回一元函數對象
sort(vec.begin(), vec.end(), greater<int>()); //從大到小對vector進行排序 find\_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70)); find\_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70));
下面給出bind1st綁定過程圖,二元函數對象綁定了第一個數為70,變?yōu)橐辉瘮祵ο?,傳遞給find_if泛型算法,此時find_if所實現的功能就是:找出有序降序數組中第一個小于70的數,所以find_if返回指向65元素的迭代器

綁定器
C++ STL
bind1st 將operator()的第一個形參綁定成一個確定的值
bind2nd 將operator()的第二個形參綁定成一個確定的值
代碼1
#include <iostream>
#include <vector>
#include <functional>
#include <algorithm>
#include <ctime>
using namespace std;
template<typename Container>
void printerContainer(Container & _container) {
typename Container::iterator it_begin = _container.begin();
typename Container::iterator it_end = _container.end();
while (it_begin != it_end) {
cout << *it_begin <<" " ;
++it_begin;
}
}
int main() {
vector < int> vec;
srand(time(nullptr));
for (int i = 0; i < 20; i++) {
vec.push_back((rand() % 100 + 1));
}
printerContainer<vector < int>>(vec);
vector< int>::iterator it_begin= vec.begin();
vector< int>::iterator it_end = vec.end();
sort(it_begin, it_end);//默認小到大排序
cout << endl;
printerContainer<vector < int>>(vec);
cout << endl;
//greater二元函數對象
sort(it_begin, it_end,greater<int>());//大到小排序
printerContainer<vector < int>>(vec);
cout << endl;
//將70按順序插入容器中,找到第一個小于70的元素
//庫里提供的less,greater都是二元的函數對象
//greater a>b
//less a<b;
//綁定器 + 二元函數對象 => 一元函數對象
//bind1st: + greater bool operator()(70, const _Ty& _Right)
//greater
//constexpr bool operator()(const _Ty& _Left, const _Ty& _Right) const
//{ // apply operator> to operands
// return (_Left > _Right);
//}
//bind2nd: + less bool operator()(const _Ty& _Left, 70)
vector<int>::iterator it_findValue=find_if(it_begin, it_end, bind1st<greater<int>, int>(greater<int>(), 70));
if (it_findValue != it_end) {
vec.insert(it_findValue, 70);
}
printerContainer<vector < int>>(vec);
cout << endl;
system("pause");
return 0;
}
綁定器 + 二元函數對象 => 一元函數對象
bind1st和bind2nd的底層實現原理
自己實現綁定器,代碼如下
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <functional>
#include <ctime>
using namespace std;
template<typename Container>
void printContainter(Container _container) {
typename Container::iterator it_begin = _container.begin();
typename Container::iterator it_end = _container.end();
for (; it_begin != it_end; ++it_begin) {
cout << *it_begin << " ";
}
cout << endl;
}
//將二元函數對象分裝,返回一元函數對象
template<typename Pr, typename T>
class MyBindList2 {
public:
MyBindList2<Pr,T>(Pr _pr, T _val):_mPr(_pr),_mVal(_val) {}
bool operator()(T _paremeter) {
return _mPr(_mVal, _paremeter);
}
private:
Pr _mPr;
T _mVal;
};
//Iterator 迭代器
//Pr 一元函數對象
template<typename Iterator , typename Pr>
Iterator my_find_if_v2(Iterator it_begin, Iterator it_end, Pr _pre) {
for (; it_begin != it_end; ++it_begin) {
if (_pre(*it_begin)) { return it_begin; }
}
return it_end;
}
int main() {
vector<int> v1;
srand(time(nullptr));
for (int i = 0; i < 10; i++) {
v1.push_back((rand() % 100 + 1));
}
printContainter<vector<int>>(v1);
//升序
sort(v1.begin(), v1.end(), less<int>());
//sort(v1.begin(), v1.end(), greater<int>()); 降序
printContainter<vector<int>>(v1);
/* 找到第一個大于40數字前插入40 */
// 方法 一
#if 0
vector<int>::iterator it_begin = v1.begin();
vector<int>::iterator it_end = v1.end();
for (; it_begin!=it_end; ++it_begin) {
if (*it_begin > 40) { break ;}
}
if (it_begin != it_end) {
v1.insert(it_begin,40);
}
printContainter<vector<int>>(v1);
#endif
// 方法 二 自己實現Bind1st
#if 0 自己實現Bind1st
vector<int>::iterator it_find = my_find_if_v2<vector<int>::iterator, MyBindList2<less<int>, int>>(v1.begin(), v1.end(), MyBindList2<less<int>, int>(less<int>(), 40));
v1.insert(it_find, 40);
printContainter<vector<int>>(v1);
#endif
// 方法 三 調用庫的Bind1st
vector<int>::iterator find_it2=find_if<vector<int>::iterator, binder1st<less<int>>>(v1.begin(), v1.end(), bind1st<less<int>, int>(less<int>(), 40));
v1.insert(find_it2, 40);
printContainter<vector<int>>(v1);
system("pause");
return 0;
}
上面代碼自己實現泛型算法my_find_if,用于找到容器中指定的位置,插入元素my_find_if 是一個函數模板,參數1,參數2是兩個迭代器指向起始和結束位置,在這兩個迭代器之間進行遍歷,遍歷是否滿足的條件由第三個參數決定,第三個參數是一個一元函數對象,由于STL現成提供的greater,less都是二元函數對象,所以我們自己需要實現一元函數對象,這個一元函數對象通過提供的二元函數對象和參數進行封裝,封裝后就是myBind1st,myBind1st底層 operator()(parameter1) 中實際調用的函數二元函數對象的operator()( parameter1 ,parameter2)
vector<int>::iterator it_findValue = my_find_if(it_begin, it_end, myBind1st<greater<int>, int>(greater<int>(), 70));
以上就是詳解C++11中綁定器bind的原理與使用的詳細內容,更多關于C++11綁定器bind的資料請關注腳本之家其它相關文章!

