精通Cocos2d-x游戏开发(基础卷)
上QQ阅读APP看书,第一时间看更新

5.5 Lambda特性

lambda是一个非常好的新特性,当需要添加一个临时的函数时,使用lambda会让你感受到满满的幸福,auto和lambda是笔者最最喜欢的C++新特性。lambda的写法如下:

[函数外部对象参数](函数参数)->返回值类型 { 函数体 }

❏[ ]中的函数外部对象参数,允许在函数体内直接调用函数外部的参数。

❏()中的函数参数,同正常函数的参数无异,是每次函数调用传入的变量。

❏->后面跟着函数返回值的类型。

❏{ }中可以编写逻辑,并使用[ ]和()中传入的参数。

定义在lambda函数相同作用域的参数引用也可以被使用,这种参数集合一般被称为闭包,[ ]中可以填写下面几种类型的参数,将定义lambda函数作用域内的变量传入函数体中。

❏[]没有任何参数,这种情况下不传入外部参数。

❏[a, &b] 传入变量a的值以及变量b的引用。

❏[&] 以引用方式传入所有变量

❏[=] 以传值方式传入所有变量,值不可被修改

❏[&, a] 除了a用传值方式传入,其他所有变量用传值方式传入。

❏[=, &a] 除了a用引用方式传入,其他所有变量用引用方式传入。

下面编写一个测试例子,当在lambda函数中使用了=传入的参数,且对引用参数或外部参数进行赋值操作后,会产生意想不到的结果,而在使用&时需要注意的是引用对象的生命周期。

int a, b, c;
auto fun0 = [&]() -> void { a = 1; b = 2; c = 3; };
auto fun1 = [=]() -> int { return 2 * 3; };
auto fun2 = [=, &a, &b]() -> void { ++a; b += c + a; };
auto fun3 = [=]() -> int { return a + c; };
//a、b、c 分别为1、2、3
fun0();
//c = 6
c = fun1();
//a = 2 b = 858993456 c = 6
fun2();
//b = 1717986916
b = fun3();

当lambda被定义在类的成员函数中时,lambda可以调用该类的private函数;当lambda调用该类的成员函数时,操作成员变量或其他成员函数时,需要将this传入,=和&会传入this

使用std::function可以存储lambda函数。例如,可以用function<void()>来存放fun0,function<int()>来存放fun1,带参数的函数可以在()内输入参数类型,在使用 function 时要包含头文件functional。

#include <functional>
function<void()> f1 = fun0;
function<int()> f2 = fun1;

function还可以用于存放普通函数,静态函数和类的公有成员函数,前面两者和lambda的用法一样,直接将函数名赋值给function对象即可(无法识别重载的函数),但类的成员函数需要使用bind来绑定。

void foo(int);
void foo(char*);
//编译失败,需要将void foo(char*)改名或移除
//标准并未定义,应该是编译器实现的问题
function<void(int)> f1 = foo;
ClassA* obj = new ClassA();
function<void(int)> f2 =bind(&ClassA::memberFun1, obj,std::placeholders:: _1);
function<void(int, char)> f3 = bind(&ClassA::memberFun2, obj , std:: placeholders::_1, std::placeholders::_2);

使用bind绑定成员函数和对象指针,使用placeholders占位符来表示函数的参数数量,placeholders的后缀依次从1~N。