lambda 表达式可以方便地构造匿名函数,如果你的代码里面存在大量的小函数,而这些函数一般只被调用一次,那么不妨将他们重构成 lambda 表达式。
C++11 的 lambda 表达式规范如下:
[ capture ] ( params ) mutable exception attribute -> ret { body } (1)
[ capture ] ( params ) -> ret { body } (2)
[ capture ] ( params ) { body } (3)
[ capture ] { body } (4)
其中
(1) 是完整的 lambda 表达式形式,
(2) const 类型的 lambda 表达式,该类型的表达式不能改捕获(“capture”)列表中的值。
(3)省略了返回值类型的 lambda 表达式,但是该 lambda 表达式的返回类型可以按照下列规则推演出来:
如果 lambda 代码块中包含了 return 语句,则该 lambda 表达式的返回类型由 return 语句的返回类型确定。如果没有 return 语句,则类似 void f(…) 函数。
(4)省略了参数列表,类似于无参函数 f()。
此外,params 指定 lambda 表达式的参数。
ret是返回值类型。(选填)
body是函数体
exception说明lambda表达式是否抛出异常以及何种异常
attribute用来声明属性
capture 指定了在可见域范围内 lambda 表达式的代码内可见得外部变量的列表
具体解释如下:
[a,&b] a变量以值的方式呗捕获,b以引用的方式被捕获。
[this] 以值的方式捕获 this 指针。
[&] 以引用的方式捕获所有的外部自动变量。
[=] 以值的方式捕获所有的外部自动变量。
[] 不捕获外部的任何变量。
mutable 修饰符说明 lambda 表达式体内的代码可以修改按值被捕获的变量,并且可以访问被捕获对象的 non-const 方法。
虽然按值捕获的变量值均补复制一份存储在lambda表达式变量中, 修改他们也并不会真正影响到外部,但我们却仍然无法修改它们。
那么如果希望去修改按值捕获的外部变量,需要显示指明lambda表达式为mutable。
需要注意:被mutable修饰的lambda表达式就算没有参数也要写明参数列表。
原因:lambda表达式可以说是就地定义仿函数闭包的“语法糖”。它的捕获列表捕获住的任何外部变量,最终均会变为闭包类型的成员变量。按照C++标准,lambda表达式的operator()默认是const的,一个const成员函数是无法修改成员变量的值的。而mutable的作用,就在于取消operator()的const。
因此,没有捕获变量的lambda表达式(本身的this指针就丢失掉)可以直接转换为函数指针,而捕获变量的lambda表达式则不能转换为函数指针。
int a = 0;
auto f1 = [=] { return a++; }; //error
auto f2 = [=] () mutable { return a++; }; //OK
auto f2 = [&] { return a++; }; //OK
auto f = [=] {return a};
a += 1;
cout<<f()<<endl; //输出结果为0;
lambda表达式可以认为是一个带有operator()的类,即仿函数,因此我们可以使用std::function和std::bind来存储和操作它
void func(void* arg1){}
void* arg;
std::function<void()> fn = [arg, func] { func(arg); };
#include <iostream>
#include <functional>
using namespace std;
class A
{
public:
void H() {}//看着是无参,其实第一个参数是this指针
};
void Fun(A a)
{
}
int main()
{
int i = 8;
std::function<void()> fn = [i]()mutable { i++; };
cout<<i<<endl;
typedef void (*Ptr)(int);
// Ptr p = [&](int p){cout<<p<<endl;cout<<i<<endl;};
Ptr p = [](int p){cout<<p<<endl;};
p(9);
std::function<void(int)> ptr = [&](int p){cout<<p<<endl;cout<<i<<endl;};
ptr(8);
A a;
std::function<void()> f_1 = std::bind(&A::H, a);
std::function<void()> f_2 = std::bind(Fun, a);
std::function<void()> f_3 = [a]()mutable{a.H();};
return 0;
}