昨天手動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]:通過傳值方式捕獲當前對象;