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。