http://www.cnblogs.com/haippy/archive/2013/05/31/3111560.html
很多语言都提供了 lambda 表达式,如 Python,Java 8。lambda 表达式可以方便地构造匿名函数,如果你的代码里面存在大量的小函数,而这些函数一般只被调用一次,那么不妨将他们重构成 lambda 表达式。
C++11 的 lambda 表达式规范如下:
[ capture ] ( params ) mutable exception attribute -> ret { body } | (1) | |
[ capture ] ( params ) -> ret { body } | (2) | |
[ capture ] ( params ) { body } | (3) | |
[ capture ] { body } |
其中
- (1) 是完整的 lambda 表达式形式,
- (2) const 类型的 lambda 表达式,该类型的表达式不能改捕获("capture")列表中的值。
- (3)省略了返回值类型的 lambda 表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来:
- 如果 lambda 代码块中包含了 return 语句,则该 lambda 表达式的返回类型由 return 语句的返回类型确定。
- 如果没有 return 语句,则类似 void f(...) 函数。
- 省略了参数列表,类似于无参函数 f()。
mutable 修饰符说明 lambda 表达式体内的代码可以修改被捕获的变量,并且可以访问被捕获对象的 non-const 方法。
exception 说明 lambda 表达式是否抛出异常(noexcept
),以及抛出何种异常,类似于void f() throw(X, Y)。
attribute 用来声明属性。
另外,capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表,具体解释如下:
[a,&b]
a变量以值的方式呗捕获,b以引用的方式被捕获。[this]
以值的方式捕获 this 指针。[&]
以引用的方式捕获所有的外部自动变量。[=]
以值的方式捕获所有的外部自动变量。[]
不捕获外部的任何变量。- [var]表示值传递方式捕捉变量var;
- [=]表示值传递方式捕捉所有父作用域的变量(包括this);
- [&var]表示引用传递捕捉变量var;
- [&]表示引用传递方式捕捉所有父作用域的变量(包括this);
- [this]表示值传递方式捕捉当前的this指针。
在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。
此外,params 指定 lambda 表达式的参数。
http://blog.csdn.net/xqs83/article/details/7612866
- lambda-introducer (捕获字段)
- lambda-parameter-declaration-list (变量列表)
- mutable-specification (捕获的变量可否修改)
- exception-specification (异常设定)
- lambda-return-type-clause (返回类型)
- compound-statement (函数体)
外部变量的捕获规则
默认情况下,即捕获字段为 [] 时,lambda表达式是不能访问任何外部变量的,即表达式的函数体内无法访问当前作用域下的变量。
如果要设定表达式能够访问外部变量,可以在 [] 内写入 & 或者 = 加上变量名,其中 & 表示按引用访问,= 表示按值访问,变量之间用逗号分隔,比如 [=factor, &total] 表示按值访问变量 factor,而按引用访问 total。
不加变量名时表示设置默认捕获字段,外部变量将按照默认字段获取,后面在书写变量名时不加符号表示按默认字段设置,比如下面三条字段都是同一含义:
参数列表
lambda表达式的参数列表基本和函数的一致,不过有如下限制:
- 参数列表不能有默认参数
- 不能是可变参数列表
- 所有的参数必须有个变量名
如果你不提供 mutable-specification, exception-specification, 以及 lambda-return-type-clause,参数列表是也可以省略的。如下面的表达式:
能否修改捕获的变量
如果在参数列表后加上了 mutable,则表示表达式可以修改按值捕获的外部变量的拷贝。
异常设置
和函数一样,可以用 throw 来限定表达式能够抛出哪些异常。
返回类型
如果设置返回类型,你需要在类型名前面加上 ->。如果你只有一个返回语句的话,返回类型可以省略,编译器将会为你做出判断。
函数体
lambda表达式的函数体和普通函数大致相同。
下面是lambda表达式的几个完整例子:
更多参见http://www.jb51.net/article/56147.htm
关于mutable
默认情况下,Lambda函数总是一个const函数,mutable可以取消其常量性。按照规定,一个const的成员函数是不能在函数体内修改非静态成员变量的值.
#include<iostream>
using namespace std;
int main()
{
int val = 0;
// auto const_val_lambda = [=](){ val = 3; }; wrong!!!
auto mutable_val_lambda = [=]() mutable{ val = 3; };
mutable_val_lambda();
cout<<val<<endl; // 0
auto const_ref_lambda = [&]() { val = 4; };
const_ref_lambda();
cout<<val<<endl; // 4
auto mutable_ref_lambda = [&]() mutable{ val = 5; };
mutable_ref_lambda();
cout<<val<<endl; // 5
return 0;
}
在使用Lambda函数的时候,如果需要捕捉的值成为Lambda函数的常量,我们通常会使用按值传递的方式捕捉;相反的,如果需要捕捉的值成成为Lambda函数运行时的变量,则应该采用按引用方式进行捕捉。
#include<iostream>
using namespace std;
int main()
{
int j = 10;
auto by_val_lambda = [=]{ return j + 1; };
auto by_ref_lambda = [&]{ return j + 1; };
cout<<"by_val_lambda: "<<by_val_lambda()<<endl;
cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl;
++j;
cout<<"by_val_lambda: "<<by_val_lambda()<<endl;
cout<<"by_ref_lambda: "<<by_ref_lambda()<<endl;
return 0;
}
程序输出结果如下:
by_val_lambda: 11
by_ref_lambda: 11
by_val_lambda: 11
by_ref_lambda: 12