【教程分享】Cocos2dx 3.0 -- lambda表达式的使用

Cocos2dx 3.0 版本后加入了lambda表达式,或者说C++ 11终于引入了lambda表达式,那么,什么是lambda表达式呢?

例如调用中的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;}); //不捕获时才可转换为函数指针


------------------------------------------------------------------------


下面讲下在cocos2dx 3.0 应该如何使用lambda:
我先创建一个menu ,如果不使用labmda,menu里 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(
“CloseNormal.png”,
“CloseSelected.png”,
](Object* sender)
{
Director::getInstance()->end();//直接在这里添加按钮要调用的代码
});



这种写法是不是简洁很多?当然了,也可以将回调 的代码单独取出来,这种写法的好处是可以多出调用callEnd。如下:

auto callEnd = ](Object* sender)
{
Director::getInstance()->end();//直接在这里添加按钮要调用的代码
};
auto closeItem = MenuItemImage::create(
“CloseNormal.png”,
“CloseSelected.png”,
allEnd);



默认情况下,即捕获字段为 ] 时,lambda表达式是不能访问任何外部变量的,即表达式的函数体内无法访问当前作用域下的变量。
如果要设定表达式能够访问外部变量,可以在 ] 内写入 & 或者 = 加上变量名,其中 & 表示按引用访问,= 表示按值访问,变量之间用逗号分隔,比如 =factor, &total] 表示按值访问变量 factor,而按引用访问 total。
用 & 引用来举个例子:假设点击按钮后,我要创建一个精灵。修改callEnd:

auto callEnd = ](Object* sender)
{
auto sp = Sprite::create(“Hello.png”);
sp->setPosition(Point(100,100));
this->addChild(sp,10);//这里报错
};



上面这种写法是错误的,因为表达式无法访问当前作用于的变量。下面继续改代码:

auto callEnd = &](Object* sender)
{
auto sp = Sprite::create(“Hello.png”);
sp->setPosition(Point(100,100));
this->addChild(sp,10);//perfect
};



这样就没问题了。
上面的例子都只是简单的应用。在cocos2dx用到lambda 的地方还有很多,例如创建一个监听事件:

// Make sprite1 touchable
auto sprite1 = Sprite::create();
auto listener1 = EventListenerTouchOneByOne::create();
listener1->setSwallowTouches(true);

listener1->onTouchBegan = ](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
return false;
};

listener1->onTouchMoved = ](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
target->setPosition(target->getPosition() + touch->getDelta());
};

listener1->onTouchEnded = =](Touch* touch, Event* event){
auto target = static_cast<Sprite*>(event->getCurrentTarget());
};

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);




恩,就这样子吧。
原文链接:http://blog.csdn.net/start530/article/details/19913611



感谢楼主分享,3.0新特性:867:,瞬间高大上了。。。

楼主你的文章上官网微博了,下次要多多写出精彩的教材哦!

我一直在努力…

很好的文章,顶!

由于Lambda的类型是唯一的,不能通过类型名来显式声明对应的对象?

std::function<bool(int, int) > comp = ](int x, int y){return x > y; };

:877: :877: 不错…mark一下

:2: 赞一个…

上面这种写法是错误的,因为表达式无法访问当前作用于的变量。下面继续改代码:
复制代码
auto callEnd = &](Object* sender) //这个写法非常容易使人误解,其实在这里使用=更加的恰当(或许是你这个例子举的不好)
{
auto sp = Sprite::create(“Hello.png”);
sp->setPosition(Point(100,100));
this->addChild(sp,10);//perfect
};

:14: :14:

楼主在引用this指针的时候使用&并不好,这个例子容易使人误解,这里并没用用到引用的功能,更应该使用=。

谢谢大神的慷慨教导

lambda好评:7::7::7:

:2: :2: :2: :2:

mark 下:7::7:

确实是个好帖子. 学习了= = 俺是挖坟专业户!

马克马克马克马克马克马克马克马克马克马克马克:14::14::14::14::14::14: