从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 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 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
#include 

class MyClass
{
    
public:
    typedef std::function 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 
#include 
#include 
using namespace std;
int main()
{
    vector 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]:通过传值方式捕获当前对象;

你可能感兴趣的:(从cocos2dx回调看到的std::bind,和lambda表达式)