lambda表达式是一个匿名函数,即他没有函数名,使用lambda表达式可以使代码更为简洁易懂,提高了代码的可读性
lambda表达式书写格式:[捕捉列表](参数列表)mutable->返回值类型{函数体}
捕捉列表:编译器根据[] 来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文红的变量供lambda函数使用。
- [](){}:空捕获列表,不捕获任何外部变量
- [变量名](){}:值捕获,通过拷贝方式捕获外部变量,并在lambda函数体内使用其拷贝
- [&变量名](){}:引用捕获,通过引用方式捕获外部变量,并在lambda函数体内共享其引用
- [=](){}:隐式捕获,省略捕获列表的变量,编译器将根据变量自动判断是否按值或引用捕获
- [&](){}:引用捕获,使任何外部变量按引用捕获,除非显示指定为值捕获
- [=, &intVar](){}:使用任何外部变量按值捕获,除了intVar是按引用捕获的。
参数列表:与普通函数的参数列表一致,如果不需要参数传递,则可以联通()一起省略。
mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可以省略。(即使参数列表为空)
->返回值类型:这部分也可以省略,当返回值明确的时候,编译器会自己推断,但是一般加上为好
函数体:在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。
int main()
{
int a = 1, b = 2;
auto sw = [](int &x, int &y)->void
{
int tmp = x;
x = y;
y = tmp;
};
sw(a, b);
cout << "a:" << a << " " << "b:" << b << endl;
return 0;
}


这样一来,调用lambda表达式时就不用传入参数了,但实际我们只需要用到变量a和变量b,没有必要把父作用域中的所有变量都进行捕捉,因此也可以只对父作用域中的a、b变量进行捕捉。比如:

说明一下: 实际当我们以[&]或[=]的方式捕获变量时,编译器也不一定会把父作用域中所有的变量捕获进来,编译器可能只会对lambda表达式中用到的变量进行捕获,没有必要把用不到的变量也捕获进来,这个主要看编译器的具体实现。
实际lambda底层实现使用的其实就是我们平时的仿函数类型,它的字节大小为一个字节,也就是说,lambda占的空间大小为1个字节
他和普通的仿函数一样,他们都是通过重载的()来进行调用的。
下面,我们来自定义实现一个仿函数和调用lambda查看一下他们的区别
class Add
{
public:
Add(int base)
:_base(base)
{}
int operator()(int num)
{
return _base + num;
}
private:
int _base;
};
int main()
{
int base = 1;
//函数对象
Add add1(base);
add1(1000);
//lambda表达式
auto add2 = [base](int num)->int
{
return base + num;
};
add2(1000);
return 0;
}
调试代码并转到反汇编,可以看到:

当调用lambda时

lambda他们之间是不可以相互赋值的,尽管他们实现的函数逻辑是一样的也不可以
其根本原因就是我们使用lambda时,该函数调用的类名为