C++11綁定器bind及function機制

前言之前在學muduo網絡庫時 , 看到陳碩以基于對象編程的方式,大量使用boost庫中的bindfunction機制,如今,這些概念都已引入至C++11 , 包含在頭文件<functional>中 。
本篇文章主要梳理C++綁定器相關的內容以及C++11中引入的function機制,其中綁定器主要有三種:bind1st、bind2ndbind(C++11) 。學完本篇內容,將對C++綁定器及function機制等的底層實現有深刻理解 , 那么我們開始說吧 。
函數對象首先說說函數對象,之所以說函數對象,是因為綁定器、function都涉及到該部分概念 。函數對象實際上是類調用operator()()小括號運算符重載,實現像在“調用函數”一樣的效果,因此還有個別名叫“仿函數” 。函數對象示例代碼如下:
class Print {public:void operator()(string &s) { cout << s << endl; }};int main() {string s = "hello world!";Print print; //定義了一個函數對象printprint(s);return 0;}上面代碼print(s);語句,看似像函數調用,其實是類對象print調用其小括號運算符重載print.operator(string &s) 。print就是一個函數對象,至此對函數對象就有了基本的認識 。
剖析綁定器bind1st、bind2nd了解了函數對象,接下來我們說說綁定器,為什么需要綁定器?在使用STL時經常會遇到STL算法中需要傳遞某元函數對象,比如在寫sort時 , 第三個參數決定了我們的排序規則,用來接收一個“比較器”函數對象,該函數對象是一個二元的匿名函數對象,形如greator<int>()或者less<int>() 。二元函數對象的意思是,這個函數對象的小括號運算符重載函數接收兩個參數,那么幾元就表示接收幾個參數 。下面是庫中自帶的greaterless模板類的源碼實現 , 可以看到是對小括號運算符重載的實現,sort第三個參數接收該模板類的二元匿名函數對象 。
template<typename _Tp>struct greater : public binary_function<_Tp, _Tp, bool>{_GLIBCXX14_CONSTEXPRbooloperator()(const _Tp& __x, const _Tp& __y) const{ return __x > __y; }};template<typename _Tp>struct less : public binary_function<_Tp, _Tp, bool>{_GLIBCXX14_CONSTEXPRbooloperator()(const _Tp& __x, const _Tp& __y) const{ return __x < __y; }};再回到剛才的問題,那為什么需綁定器?由于STL接口的限制,有時我們拿到的函數對象和特定STL算法中要接收的函數對象在參數上并不匹配,意思就是需要傳遞一個一元函數對象,你有一個二元函數對象,那可以通過綁定器提前綁定二元函數對象的其中一個參數,使得最終返回的是一個一元函數對象,那么從二元函數對象到一元函數對象的轉換過程 , 就需要綁定器去實現 。
如STL中的泛型算法find_if,可用來查找可變長數組vector中符合某個條件的值(這個條件比如是要大于50,要小于30,要等于25等等) 。其第三個參數需要傳遞一個一元函數對象,假如現在要找到第一個小于70的數,可將綁定器與二元函數對象結合,轉換為一元函數對象后傳遞給find_if 。
我們知道系統自帶的greater<int>()less<int>()模板類對象是二元匿名函數對象 , 所以需要通過綁定器將其轉換為一元函數對象,可以通過bind1stbind2nd去綁定,顧名思義,前者對二元函數對象的第一個參數進行綁定 , 后者對二元函數對象的第二個參數進行綁定,兩個綁定器均返回一元函數對象 , 用法如下:
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));兩個綁定器分別提前綁定了一個參數,使得二元函數對象+綁定器轉換為一元函數對象:
operator()(const T &val)greater a > b ====> bind1st(greater<int>(), 70) ====> 70 > blessa < b ====> bind2nd(less<int>(),70) ====> a < 70下面給出bind1st綁定過程圖,二元函數對象綁定了第一個數為70,變為一元函數對象,傳遞給find_if泛型算法,此時find_if所實現的功能就是:找出有序降序數組中第一個小于70的數 , 所以

推薦閱讀