Lambda 表达式通常被称为匿名函数,
但从底层实现来看,
它本质上是编译器生成的匿名仿函数对象。
一.基础语法
[capture](parameter)->return_type
{
body
};
这是基本格式
[](int a,int b)->int
{
return a+b;
};
其作用与下面代码相同
int Add(int a,int b)
{
return a+b;
}
区别在于lambda是匿名的。
需要注意的是,很多代码中不会写->type,这是因为大多数情况计算机可以自己推出来。而只有在以下情况下,才需要自己去写
auto func = [](int x) -> double
{
if(x > 0)
return 1;
else
return 3.14;
};
这种形式无法确定返回值类型,因此需要写上。
二.使用方法
Lambda 表达式生成的是一个匿名类型,
由于我们无法写出这个类型名,
因此通常使用 auto 接收 Lambda 对象。
auto add =
[](int a,int b)
{
return a+b;
};
由于这种匿名函数的展开是一种class类,而我们本身不知道这个类的名字,类似于 __Lambda123形式。所有需要auto,将这个任务交给计算机即可。
最终直接调用add即可。
cout<<add(10,20);
三.Lambda底层原理
Lambda 不是函数,而是一个由编译器生成的匿名类对象(仿函数对象)。
首先我们看一下仿函数
class Add
{
public:
int operator()(int a, int b)
{
return a + b;
}
};
Add add;
cout << add(10, 20);
看起来像函数调用。
实际上是:
add.operator()(10,20);
从这里大家就可以发现,这种调用方法不正是lambda的调用方法吗,没错。
在计算机内部当你写了如下代码时
auto add =
[](int a, int b)
{
return a + b;
};
计算机会将其转换为我们熟悉的形态。
class __Lambda
{
public:
int operator()(int a,int b)
{
return a+b;
}
};
其实就是一个仿函数,区别只是仿函数是你自己写类,Lambda是编译器帮你写类。
四.捕获列表(Lambda 灵魂)
捕获的本质:
编译器将捕获的变量变成 Lambda 对象的数据成员。
因为 Lambda 内部看不到外部变量。
所以值捕获非常重要。
int a = 10;
auto func =
[a]
{
cout<<a;
};
传进去的是拷贝版,不方便改值,自然而然的就有了引用捕获。
int a = 10;
auto func =
[&a]
{
cout<<a;
};
全部值捕获
[a,b,c]太麻烦。
直接用[=]表示全部值捕获。
例如:
int a=10;
int b=20;
auto func =
[=]
{
cout<<a+b;
};
全部引用捕获
[&]
混合捕获
[=,&a]意思是其他变量值捕获以及a引用捕获
五.mutable(可变的)
原本情况下是不可以更改副本的。
int a = 10;
auto func =
[a]
{
a++;
};//这是会报错的
这是因为默认是operator() const
只需加上mutable就可以了
[a]() mutable
{
a++;
}
而这只是对副本的修改。
六.经典应用
vector<int> v =
{
5,3,7,1,9
};
sort(v.begin(),v.end(),
[](int a,int b)
{
return a>b;
});//降序排列
auto it =
find_if(
v.begin(),
v.end(),
[](int x)
{
return x > 5;
}
);//查找
thread t(
[]
{
cout << "Hello Lambda";
});t.join();//线程