從cocos2dx回調看到的std::bind,和lambda表達式

昨天手動binding C++的回調到Lua的時候,用到了lambda表達式。今天專門看了一下cocos2dx的回調操作。都是個人筆記,有問題歡迎指正, 不負任何法律責任,-_-
參考文章, 果凍想

1. 首先也是從這幾個回調開始看

#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__)

全是關于std::bind的宏定義。因為cocos2dx中只會用到綁定成員函數的情況,所以,這里只看一下,綁定成員函數的用法。

2.簡單看一下std::bind的源碼,在functional.h的頭文件中。

// TEMPLATE FUNCTION bind (implicit return type)沒有返回值
template<class _Fx,
    class... _Types> inline
    _Binder<_Unforced, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args)
    {   // bind a callable object with an implicit return type
    return (_Binder<_Unforced, _Fx, _Types...>(
        _STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...));
    }

    // TEMPLATE FUNCTION bind (explicit return type)有返回值的
template<class _Ret,
    class _Fx,
    class... _Types> inline
    _Binder<_Ret, _Fx, _Types...> bind(_Fx&& _Func, _Types&&... _Args)
    {   // bind a callable object with an explicit return type
    return (_Binder<_Ret, _Fx, _Types...>(
        _STD forward<_Fx>(_Func), _STD forward<_Types>(_Args)...));
    }

會發現下面還有一個枚舉,是關于參數占位符的枚舉,一共20個,所以用std::bind最多支持20個參數的函數的綁定。

3.綁定成員函數

這里主要是看綁定成員函數的基本用法:
首先,我有一個類,需要一個std::function的參數

#include<iostream>
#include <functional>

class MyClass
{
    
public:
    typedef std::function<void(std::string)> myCallBack;

    MyClass(std::string name);
    ~MyClass();
    std::string getName();
    void setName(std::string name);
    void printInfo();
    void setCallBack(myCallBack callBack); //需要一個std::function的方法
private:
    std::string _name;
    myCallBack _callBack;
};

然后看一下調用setCallBack的方法:

auto myClass = MyClass("12121");
myClass.setCallBack(std::bind(&HelloWorld::myClassCallBack/*函數名*/, this/*調用者*/, std::placeholders::_1/*參數*/));

因為myClassCallBack需要一個參數,所以這里草穿進去一個參數占位符,就可以接受調用過程中實際傳過來的參數了。如果有多個參數,就需要多個參數占位符。這里的參數占位符也可以替換成這種:

myClass.setCallBack(std::bind(&HelloWorld::myClassCallBack, this, "zzz test!!"));

這樣的話,下面的myClassCallBack中傳進來的就是"zzz test!!",下面是成員函數:

void HelloWorld::myClassCallBack(std::string str)
{
    CCLOG("===============   %s", str.c_str());
}

4.綁定非成員函數

綁定非成員函數的時候,可以把調用者去掉就可以了:

int add1(int i, int j, int k) {  
    return i + j + k;  
} 
auto add2 = std::bind(add1, std::placeholders::_1, std::placeholders::_2, 10);  
    // 函數add2 = 綁定add1函數,參數1不變,參數2不變,參數3固定為10.  

還有一個需要注意的地方就是參數占位符如果調換位置,在實際調用過程中,傳入參數也會調換位置。這樣就比較靈活,一個函數通過bind的時候調換參數的位置,設置可以實現函數重載的功能。

5.然后接上面的看一下lambda表達式設置回調

auto func = [](std::string str) {
        CCLOG("==========lambda=======%s", str.c_str());
    };
myClass.setCallBack(func);

這個就比較簡單了,具體lambda的用法,以后用到了再深究吧

lambda表達式基本用法

1)聲明Lambda表達式

Lambda表達式完整的聲明格式如下:

[capture list] (params list) mutable exception-> return type { function body }

各項具體含義如下

  • capture list:捕獲外部變量列表
  • params list:形參列表
  • mutable指示符:用來說用是否可以修改捕獲的變量
  • exception:異常設定
  • return type:返回類型
  • function body:函數體
2)具體用法
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
    vector<int> myvec{ 3, 2, 5, 7, 3, 2 };
    sort(myvec.begin(), myvec.end(), [](int a, int b) -> bool { return a < b; });   // Lambda表達式
    cout << "lambda expression:" << endl;
    for (int it : myvec)
        cout << it << ' ';
}
3)捕獲外部變量

[]:默認不捕獲任何變量;
[=]:默認以值捕獲所有變量;
[&]:默認以引用捕獲所有變量;
[x]:僅以值捕獲x,其它變量不捕獲;
[&x]:僅以引用捕獲x,其它變量不捕獲;
[=, &x]:默認以值捕獲所有變量,但是x是例外,通過引用捕獲;
[&, x]:默認以引用捕獲所有變量,但是x是例外,通過值捕獲;
[this]:通過引用捕獲當前對象(其實是復制指針);
[*this]:通過傳值方式捕獲當前對象;

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容