昨天手动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]:通过传值方式捕获当前对象;