程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> C++11中的std::bind

C++11中的std::bind

編輯:關於C語言
 

這幾天學習Cocos2d-x,看到了以下的一段代碼:

// new callbacks based on C++11#define CC_CALLBACK_0(__selector__,__target__, ...) std::bind(&__selector__,__target__, ##__VA_ARGS__)#define CC_CALLBACK_1(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, ##__VA_ARGS__)#define CC_CALLBACK_2(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, ##__VA_ARGS__)#define CC_CALLBACK_3(__selector__,__target__, ...) std::bind(&__selector__,__target__, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, ##__VA_ARGS__)
都是定義的一些宏,如果你看了上面的這段代碼,覺的很簡單,那麼這篇文章你完全可以pass了;如果你對上面定義的這些宏,完全不知道是什麼意思,那麼,這篇文章就屬於你,完全屬於你的菜。

通過這篇文章,我將帶你進入C++11中std::bind的世界,讓我們起航吧。

先來看看std::bind1st和std::bind2nd
bind是這樣一種機制,它可以預先把指定可調用實體的某些參數綁定到已有的變量,產生一個新的可調 用實體,這種機制在回調函數的使用過程中也頗為有用。C++98中,有兩個函數bind1st和bind2nd,它們分別可以用來綁定functor的第 一個和第二個參數,它們都是只可以綁定一個參數。各種限制,使得bind1st和bind2nd的可用性大大降低。

如果通過上面的內容,你還沒有明白std::bind1st和std::bind2nd到底是何方聖神到底是什麼東西,那就看這段代碼示例:

#include <iostream>#include <functional>#include <algorithm>#include <vector>using namespace std;int main(){
vector<int> coll;
for (int i = 1; i <= 10; ++i)
{
coll.push_back(i);
}

// 查找元素值大於10的元素的個數
// 也就是使得10 < elem成立的元素個數
int res = count_if(coll.begin(), coll.end(), bind1st(less<int>(), 10));
cout << res << endl;

// 查找元素值小於10的元素的個數
// 也就是使得elem < 10成立的元素個數
res = count_if(coll.begin(), coll.end(), bind2nd(less<int>(), 10));
cout << res << endl;

return 0;}
通過上面的代碼明白了std::bind1st和std::bind2nd了麼?還沒有明白?好吧,我接著往細了講。

對於上面的代碼,less<int>()其實是一個仿函數,如果沒有std::bind1st和std::bind2nd,那麼我們可以這樣使用less<int>(),代碼如下:

less<int> functor = less<int>();bool bRet = functor(10, 20); // 返回true
看到了麼?less<int>()這個仿函數對象是需要兩個參數的,比如10<20進行比較,那麼10叫做left參數,20叫做right參數。

當使用std::bind1st的時候,就表示綁定了left參數,也就是left參數不變了,而right參數就是對應容器中的element;
當使用std::bind2nd的時候,就表示綁定了right參數,也就是right參數不變了,而left參數就是對應容器中的element。
這下應該講明白了。

再來看看std::bind
C++11中提供了std::bind。bind()函數的意義就像它的函數名一樣,是用來綁定函數調用的某些參數的。

bind的思想實際上是一種延遲計算的思想,將可調用對象保存起來,然後在需要的時候再調用。而且這種綁定是非常靈活的,不論是普通函數、函數對象、還是成員函數都可以綁定,而且其參數可以支持占位符,比如你可以這樣綁定一個二元函數auto f = bind(&func, _1, _2);,調用的時候通過f(1,2)實現調用。

簡單的認為就是std::bind就是std::bind1st和std::bind2nd的加強版。

怎麼使用std::bind
一個知識點厲不厲害,歸根到底還是要經過實踐的考驗,下面就來看看std::bind到底怎麼用。

先看看《C++11中的std::function》中那段代碼,std::function可以綁定全局函數,靜態函數,但是綁定類的成員函數時,必須要借助std::bind的幫忙。但是話又說回來,不借助std::bind也是可以完成的,只需要傳一個*this變量進去就好了,比如:

#include <iostream>#include <functional>using namespace std;class View{public:
void onClick(int x, int y)
{
cout << "X : " << x << ", Y : " << y << endl;
}};// 定義function類型, 三個參數
function<void(View, int, int)> clickCallback;int main(int argc, const char * argv[]){
View button;

// 指向成員函數
clickCallback = &View::onClick;

// 進行調用
clickCallback(button, 10, 123);
return 0;}
再來一段示例談談怎麼使用std::bind代碼:

#include <iostream>#include <functional>using namespace std;int TestFunc(int a, char c, float f){
cout << a << endl;
cout << c << endl;
cout << f << endl;

return a;}int main(){
auto bindFunc1 = bind(TestFunc, std::placeholders::_1, 'A', 100.1);
bindFunc1(10);

cout << "=================================\n";

auto bindFunc2 = bind(TestFunc, std::placeholders::_2, std::placeholders::_1, 100.1);
bindFunc2('B', 10);

cout << "=================================\n";

auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1);
bindFunc3(100.1, 30, 'C');

return 0;}
上面這段代碼主要說的是bind中std::placeholders的使用。 std::placeholders是一個占位符。當使用bind生成一個新的可調用對象時,std::placeholders表示新的可調用對象的第 幾個參數和原函數的第幾個參數進行匹配,這麼說有點繞。比如:

auto bindFunc3 = bind(TestFunc, std::placeholders::_2, std::placeholders::_3, std::placeholders::_1);

bindFunc3(100.1, 30, 'C');
可以看到,在bind的時候,第一個位置是TestFunc,除了這個,參數的第一個位置為占位符std::placeholders::_2,這就表示,調用bindFunc3的時候,它的第二個參數和TestFunc的第一個參數匹配,以此類推。

以下是使用std::bind的一些需要注意的地方:

bind預先綁定的參數需要傳具體的變量或值進去,對於預先綁定的參數,是pass-by-value的;
對於不事先綁定的參數,需要傳std::placeholders進去,從_1開始,依次遞增。placeholder是pass-by-reference的;
bind的返回值是可調用實體,可以直接賦給std::function對象;
對於綁定的指針、引用類型的參數,使用者需要保證在可調用實體調用之前,這些參數是可用的;
類的this可以通過對象或者指針來綁定。
為什麼要用std::bind
當我們厭倦了使用std::bind1st和std::bind2nd的時候,現在有了std::bind,你完全可以放棄使用std::bind1st和std::bind2nd了。std::bind綁定的參數的個數不受限制,綁定的具體哪些參數也不受限制,由用戶指定,這個bind才是真正意義上的綁定。

在Cocos2d-x中,我們可以看到,使用std::bind生成一個可調用對象,這個對象可以直接賦值給std::function對象;在類中有一個std::function的變量,這個std::function由std::bind來賦值,而std::bind綁定的可調用對象可以是Lambda表達式或者類成員函數等可調用對象,這個是Cocos2d-x中的一般用法。

以後遇到了“奇葩”用法再繼續總結了,一次也總結不完的。

總結
又是一篇總結怎麼使用的文章,如果你覺的看的不過瘾,覺的我的文章寫的不痛不癢的,還想看點更深的東西,比如std::bind是如何實現的啊?好吧,這篇文章確實沒有說這些深層次的東西,推薦這篇文章《bind原理圖釋》,希望這篇文章能滿足你哦。

 
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved