在介绍3.0新的触摸机制之前,我们有必要先介绍一下3.0新引进的C++ 11的Lambda表达式。
1. Lambda表达式
首先,什么是Lambda表达式呢?
Lambda表达式是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的Lambda抽象,是一个匿名函数,即没有函数名的函数。相信有数学背景的孩子,现在是不是感觉到Lambda这个读音很耳熟呢?嘿嘿
基本语法如下:
[捕获列表](形参列表) mutable->返回值类型 复合语句
其中除了“[]”(其中捕获列表可以为空)和“复合语句”(相当于具名函数定义的函数体),其它都是可选的。它的类型是唯一的具有成员operator()的非联合的类类型,称为闭包类型(closure type)。
例如调用<algorithm>中的std::sort,ISO C++ 98 的写法是要先写一个compare函数:
bool compare(int&a, int&b)
{
return a>b; //降序排序
}
然后,再这样调用:
sort(a, a+n, compare);
然而,用ISO C++ 11 标准新增的Lambda表达式,可以这么写:
sort(a, a+n, [](int a, int b){return a>b;}); //降序排序
现在,是不是觉得代码简洁了很多呢?
由于Lambda的类型是唯一的,不能通过类型名来显式声明对应的对象,但可以利用auto关键字和类型推导:
auto f=[](int a, int b){return a>b;};
和其它语言的一个较明显的区别是Lambda和C++的类型系统结合使用,如:
auto f=[=](int a, int b){ return a>x;});//x被捕获复制
int x=0, y=1;
auto g=[&](int x){return ++y;});//y被捕获引用,调用g后会修改y,需要注意y的生存期
bool (*fp)(int,int)=[](int a,int b){return a>b;});//不捕获时才可转换为函数指针
Lambda表达式可以嵌套使用。
2. 在cocos2d-x 3.0中使用Lambda
例如创建一个MenuItem,如果不使用Lambda,需要为这个item写一个回调函数,代码如下:
auto closeItem=MenuItemImage::create(
"CloseNormal.png",
"CloseSelected.png",
CC_CALLBACK_1(HelloWorld::menuCloseCallback,this));
void HelloWorld::menuCloseCallback(Object* sender)
{
Director::getInstance()->end();
}
如果使用Lambda后,代码如下:
auto closeItem=MenuItemImage::create(
"CloseNoraml.png",
"CloseSeleceted.png",
[](Object* pSender)
{
Director::getInstance()->end(); //直接在这边添加代码
});
是不是瞬间感觉到代码简洁了呢?这里还有另外一种写法,就是将回调的代码取出来,这样有一个好处就是可以多处调用callEnd。
auto callEnd=[](Object* pSender)
{
Director::getInstance()->end(); //这里直接添加代码
};
auto closeItem=MenuItemImage::create("CloseNormal.png","CloseSelected.png",callEnd);
另外需要说的是:在默认情况下,即捕获字段为[]时,lambda表达式是不能访问外部变量的,即表达式的函数体内无法访问当前作用域下的变量。
如果要设定表达式能够访问外部变量,可以在[]内写入&或者=加上变量名,其中&表示按引用访问,=表示按值访问,变量之间用逗号分隔,比如[=number, &name]表示按值访问变量number,而按引用访问name。
用&引用来举个例子:假设点击按钮后,我要创建一个精灵。修改callEnd:
auto callEnd=[](Object* pSender)
{
auto sprite=Sprite::create("Hello.png");
sprite->setPosition(Point(50,50));
this->addChild(sprite,5); //这里会报错
}
上面这种写法是错误的,因为表达式无法访问当前作用域的变量。修改代码如下:
auto callEnd=[&](Object* pSender)
{
auto sprite=Sprite::create("Hello.png");
sprite->setPosition(Point(50,50));
this->addChild(sprite,5); //正常运行
}
---------参考自百度百科和天涯海阁