詳解C++11中綁定器bind的原理與使用
bind1st和bind2nd什么時(shí)候會(huì)用到
bind用于綁定可調(diào)用 (Callable) 對象(函數(shù)對象、指向函數(shù)指針、到函數(shù)引用、指向成員函數(shù)指針或指向數(shù)據(jù)成員指針)和其參數(shù)。返回值為綁定成功后的函數(shù)對象
C++11中引入的function機(jī)制,其中綁定器主要有三種:bind1st、bind2nd、bind(C++11)
函數(shù)對象
盡管函數(shù)指針被廣泛用于實(shí)現(xiàn)函數(shù)回調(diào),但C++還提供了一個(gè)重要的實(shí)現(xiàn)回調(diào)函數(shù)的方法,那就是函數(shù)對象。函數(shù)對象(也稱“函數(shù)符”)是重載了“()”操作符的普通類對象。因此從語法上講,函數(shù)對象與普通的函數(shù)行為類似。
用函數(shù)對象代替函數(shù)指針有幾個(gè)優(yōu)點(diǎn):
首先,因?yàn)閷ο罂梢栽趦?nèi)部修改而不用改動(dòng)外部接口,因此設(shè)計(jì)更靈活,更富有彈性。函數(shù)對象也具備有存儲(chǔ)先前調(diào)用結(jié)果的數(shù)據(jù)成員。在使用普通函數(shù)時(shí)需要將先前調(diào)用的結(jié)果存儲(chǔ)在全程或者本地靜態(tài)變量中,但是全程或者本地靜態(tài)變量有某些我們不愿意看到的缺陷。
其次,在函數(shù)對象中編譯器能實(shí)現(xiàn)內(nèi)聯(lián)調(diào)用,從而更進(jìn)一步增強(qiáng)了性能。這在函數(shù)指針中幾乎是不可能實(shí)現(xiàn)的。
C++11還提供了limbda表達(dá)式來實(shí)現(xiàn)函數(shù)的靈活調(diào)用。詳見《C++ Primer Plus》第18章
函數(shù)對象實(shí)際上是類調(diào)用operator()()小括號運(yùn)算符重載,實(shí)現(xiàn)像在“調(diào)用函數(shù)”一樣的效果,因此還有個(gè)別名叫“仿函數(shù)”。函數(shù)對象示例代碼如下:
class Print { public: void operator()(string &s) { cout << s << endl; } }; int main() { string s = "hello world!"; Print print; //定義了一個(gè)函數(shù)對象print print(s); return 0; }
上面代碼print(s);語句,看似像函數(shù)調(diào)用,其實(shí)是類對象print調(diào)用其小括號運(yùn)算符重載print.operator(string &s)。print就是一個(gè)函數(shù)對象,至此對函數(shù)對象就有了基本的認(rèn)識
為什么需要綁定器?在使用STL時(shí)經(jīng)常會(huì)遇到STL算法中需要傳遞某元函數(shù)對象,比如在寫sort時(shí),第三個(gè)參數(shù)決定了我們的排序規(guī)則,用來接收一個(gè)“比較器”函數(shù)對象,該函數(shù)對象是一個(gè)二元的匿名函數(shù)對象,形如greator()或者less()。二元函數(shù)對象的意思是,這個(gè)函數(shù)對象的小括號運(yùn)算符重載函數(shù)接收兩個(gè)參數(shù),那么幾元就表示接收幾個(gè)參數(shù)。
我們知道系統(tǒng)自帶的greater()和less()模板類對象是二元匿名函數(shù)對象,但是像泛型算法find_if第三個(gè)參數(shù)接收一元函數(shù)對象,所以需要通過綁定器將其轉(zhuǎn)換為一元函數(shù)對象,可以通過bind1st和bind2nd去綁定,顧名思義,前者對二元函數(shù)對象的第一個(gè)參數(shù)進(jìn)行綁定,后者對二元函數(shù)對象的第二個(gè)參數(shù)進(jìn)行綁定,兩個(gè)綁定器均返回一元函數(shù)對象
sort(vec.begin(), vec.end(), greater<int>()); //從大到小對vector進(jìn)行排序 find\_if(vec.begin(), vec.end(), bind1st(greater<int>(), 70)); find\_if(vec.begin(), vec.end(), bind2nd(less<int>(), 70));
下面給出bind1st綁定過程圖,二元函數(shù)對象綁定了第一個(gè)數(shù)為70,變?yōu)橐辉瘮?shù)對象,傳遞給find_if泛型算法,此時(shí)find_if所實(shí)現(xiàn)的功能就是:找出有序降序數(shù)組中第一個(gè)小于70的數(shù),所以find_if返回指向65元素的迭代器
綁定器
C++ STL
bind1st 將operator()的第一個(gè)形參綁定成一個(gè)確定的值
bind2nd 將operator()的第二個(gè)形參綁定成一個(gè)確定的值
代碼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);//默認(rèn)小到大排序 cout << endl; printerContainer<vector < int>>(vec); cout << endl; //greater二元函數(shù)對象 sort(it_begin, it_end,greater<int>());//大到小排序 printerContainer<vector < int>>(vec); cout << endl; //將70按順序插入容器中,找到第一個(gè)小于70的元素 //庫里提供的less,greater都是二元的函數(shù)對象 //greater a>b //less a<b; //綁定器 + 二元函數(shù)對象 => 一元函數(shù)對象 //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; }
綁定器 + 二元函數(shù)對象 => 一元函數(shù)對象
bind1st和bind2nd的底層實(shí)現(xiàn)原理
自己實(shí)現(xiàn)綁定器,代碼如下
#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; } //將二元函數(shù)對象分裝,返回一元函數(shù)對象 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 一元函數(shù)對象 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); /* 找到第一個(gè)大于40數(shù)字前插入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 // 方法 二 自己實(shí)現(xiàn)Bind1st #if 0 自己實(shí)現(xiàn)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 // 方法 三 調(diào)用庫的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; }
上面代碼自己實(shí)現(xiàn)泛型算法my_find_if,用于找到容器中指定的位置,插入元素my_find_if 是一個(gè)函數(shù)模板,參數(shù)1,參數(shù)2是兩個(gè)迭代器指向起始和結(jié)束位置,在這兩個(gè)迭代器之間進(jìn)行遍歷,遍歷是否滿足的條件由第三個(gè)參數(shù)決定,第三個(gè)參數(shù)是一個(gè)一元函數(shù)對象,由于STL現(xiàn)成提供的greater,less都是二元函數(shù)對象,所以我們自己需要實(shí)現(xiàn)一元函數(shù)對象,這個(gè)一元函數(shù)對象通過提供的二元函數(shù)對象和參數(shù)進(jìn)行封裝,封裝后就是myBind1st,myBind1st底層 operator()(parameter1) 中實(shí)際調(diào)用的函數(shù)二元函數(shù)對象的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的原理與使用的詳細(xì)內(nèi)容,更多關(guān)于C++11綁定器bind的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C++11智能指針中的 unique_ptr實(shí)例詳解
unique是獨(dú)特的、唯一的意思,故名思議,unique_ptr可以“獨(dú)占”地?fù)碛兴赶虻膶ο?,它提供一種嚴(yán)格意義上的所有權(quán)。這篇文章主要介紹了C++11智能指針中的 unique_ptr實(shí)例詳解,需要的朋友可以參考下2020-06-06統(tǒng)計(jì)C語言二叉樹中葉子結(jié)點(diǎn)個(gè)數(shù)
這篇文章主要介紹的是統(tǒng)計(jì)C語言二叉樹中葉子結(jié)點(diǎn)個(gè)數(shù),文章以C語言二叉樹中葉子結(jié)點(diǎn)為基礎(chǔ)分享一個(gè)簡單小栗子講解,具有一定的知識參考價(jià)值,需要的小伙伴可以參考一下2022-02-02C++調(diào)用EasyX庫實(shí)現(xiàn)嫦娥奔月小游戲
這篇文章主要為大家詳細(xì)介紹了C++如何調(diào)用EasyX庫編寫一個(gè)簡單的嫦娥奔月小游戲,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下2023-09-09用Visual Studio2017寫C++靜態(tài)庫圖文詳解
這篇文章主要介紹了用Visual Studio2017寫C++靜態(tài)庫的圖文教程,需要的朋友可以參考下2017-04-04C語言/C++中如何產(chǎn)生隨機(jī)數(shù)
這里要用到的是rand()函數(shù), srand()函數(shù),和time()函數(shù)。需要說明的是,iostream頭文件中就有srand函數(shù)的定義,不需要再額外引入stdlib.h;而使用time()函數(shù)需要引入ctime頭文件2013-10-10google c++程序測試框架googletest使用教程詳解
​GoogleTest 是 Google 的 C++ 測試和模擬框架,可以幫助程序員測試C++程序的結(jié)果預(yù)期,這篇文章主要介紹了google c++程序測試框架googletest使用教程,需要的朋友可以參考下2021-08-08基于Linux系統(tǒng)調(diào)用--getrlimit()與setrlimit()函數(shù)的方法
本篇文章是對在Linux系統(tǒng)中調(diào)用getrlimit()與setrlimit()函數(shù)的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05vscode和cmake編譯多個(gè)C++文件的實(shí)現(xiàn)方法
這篇文章主要介紹了vscode和cmake編譯多個(gè)C++文件的實(shí)現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03