一、定义
lambda是一种匿名函数,即没有函数名的函数。lambda函数的语法定义为:
[捕捉列表] (参数) mutable -> 返回值类型 {函数体}
二、[捕捉列表],定义能够捕获的函数外的变量,通俗地说捕获就是匿名函数外所在作用域内的变量,这些变量可以在函数体内部调用。捕获有两种形式,按值捕获和按引用捕获。按值捕获的变量相当于和函数外作用域内同名的一个变量,在函数内对改变量的修改不会影响函数外变量。按引用捕获就是直接引用函数外作用域内的变量,在函数内对改变量的修改就是对函数外变量的修改。
[var] 表示以值传递方式捕捉变量var
[=] 表示值传递捕捉所有父作用域变量
[&var] 表示以引用传递方式捕捉变量var
[&] 表示引用传递捕捉所有父作用域变量
[this] 表示值传递方式捕捉当前的this指针
[=,&a] 表示以引用传递方式捕捉a,值传递方式捕捉其他变量
[=a,&] 表示以值传递方式捕捉a,引用传递方式捕捉其他变量
示例:
int main(int argc, char* argv[])
{
int a = 5, b = 7;
auto total = [](int x, int y)->int {return x + y; }; //接受两个参数
cout << total(a, b)<<endl; //12
auto fun1 = [=] {return a + b; }; //值传递捕捉父作用域变量
cout << fun1() << endl; //12
auto fun2 = [&](int c) {b = a + c; a = 1; }; //省略了返回值类型,引用捕获所有
fun2(3); //1 8
cout << a <<" "<< b << endl;
a = 5; b = 7; //被修改后,重新赋值
auto fun3 = [=, &b](int c) mutable {b = a + c; a = 1; }; //以值传递捕捉的变量,在函数体里如果要修改,要加mutaple,因为默认const修饰
fun3(3);
cout << a << " " <<b<< endl; //5,8
a = 5; b = 7; //被修改后,重新赋值
auto fun4 = [=](int x, int y) mutable->int {a += x; b += y; return a + b; };
int t = fun4(10, 20);
cout << t << endl; //42
cout << a <<" "<< b << endl; //5 7
return 0;
}
三、mutable
匿名函数默认是const属性,值传递的变量在函数体内不能被修改(引用传递的变量可以修改)。如果需要在函数体内去修改值传递的变量,则需要添加mutable关键字。当lambda中使用了mutable修饰符,则“参数列表”是不可以省略掉的,即使参数为空。
四、返回值类型
函数体中所有return返回的都是同一类型的话,编译器会自行判断函数的返回类型,“-> 返回值类型”可以省略。
五、lambda和static inline函数
Lambda函数可以省略外部声明的static inline函数,其相当于一个局部函数。局部函数仅属于父作用域,比起外部的static inline函数,或者是自定义的宏,Lambda函数并没有实际运行时的性能优势(但也不会差),但是Lambda函数可读性更好。父函数结束后,该Lambda函数就不再可用了,不会污染任何名字空间。
六、lambda函数与函数指针
Lambda函数并不是简单的函数指针类型,或者自定义类型;每个Lambda函数会产生一个闭包类型的临时对象(右值)。但是C++11允许Lambda函数向函数指针的转换,前提是:
(1)Lambda没有捕捉任何变量
(2)函数指针所示的函数原型,必须和Lambda有相同的调用方式
示例:
int main(int argc, char* argv[])
{
int a = 3, b = 4;
auto total = [](int x, int y)->int {return x + y; };
typedef int(*all)(int x, int y);
typedef int(*one)(int x);
all p;
p = total;
one q;
q = total; //报错,参数不一致
decltype(total) all_1 = total;
decltype(total) all_2 = p; //报错,指针无法转换为Lambda
return 0;
}
七、lambda与STL
从C++11开始,Lambda被广泛用在STL中,比如foreach。与函数指针比起来,函数指针有巨大的缺陷:1.函数定义在别处,阅读起来很困难;2.使用函数指针,很可能导致编译器不对其进行inline优化,循环次数太多时,函数指针和Lambda比起来性能差距太大。函数2指针不能应用在一些运行时才能决定的状态,在没有C++11时,只能用仿函数。使得学习STL算法的代价大大降低。
但是Lambda并不是仿函数的完全代替者。由Lambda的捕捉列表的限制造成的,仅能捕捉副作用域的变量。放函数具有天生跨作用域共享的特征。
参考: