一、lambda 表达式的作用
匿名函数是一种可调用对象,拥有函数体,但没有函数名
C++11 lambda 表达式是一个匿名函数,用它可以非常方便的表示一个函数对象,使得创建快速的、一次性的函数变得简单了。lambda 表达式有 “即用即扔” 的特点,很适合不需要重复调用且运用区域单一的情景(而不是去定义一个正式的函数)
二、lambda 表达式的定义
[capture list] (params list) mutable exception-> return type { function body };
[capture list] (params list) -> return type {function body};
[capture list] (params list) {function body};
[capture list] {function body};
capture list:
捕获外部变量列表,表示lambda表达式在一定的scope可以访问的数据
params list:
形参列表,函数无参数列表意味无参函数,形参列表与捕获列表并没有关系,形参列表是执行lambda表达式时传入的参数
mutable:
在函数体里按值捕获的变量,实质上是调用者上下文变量的只读拷贝(read-only),默认情况函数体内不能修改该拷贝,当加入 mutable
后,函数体内部可以修改这个拷贝的值,但上下文中该变量的值依然不会改变
exception:
异常设定
return type:
返回类型,当省略返回类型时,如果函数体内含有 return
语句,则按 return
语句返回类型决定返回值类型,若无则返回 void
类型
function body:
函数体
三、lambda 表达式捕获
1. 值捕获
值捕获和参数传递中的值传递类似,被捕获的值在Lambda表达式创建时通过值拷贝的方式传入,因此Lambda表达式函数体中不能修改该外部变量的值;同样,函数体外对于值的修改也不会改变被捕获的值
int a = 123;
auto f = [a] { cout << a << endl; };
f(); // 输出:123
a = 321;
f(); // 输出:123
2. 引用捕获
引用捕获的变量使用的实际上就是该引用所绑定的对象,因此引用对象的改变会改变函数体内对该对象的引用的值
int a = 123;
auto f = [&a] { cout << a << endl; };
a = 321;
f(); // 输出:321
3. 隐式捕获
- [=]:以值补获的方式捕获外部所有变量
- [&]:表示以引用捕获的方式捕获外部所有变量
int a = 123, b=321;
auto df = [=] { cout << a << b << endl; }; // 值捕获
auto rf = [&] { cout << a << b << endl; }; // 引用捕获
四、示例代码
double g_bb = 11.2;
void func()
{
auto fun1 = [&](int a, int b) -> int { return a+b; }; // lambda 表达式本质是一个函数对象,还需要调用 fun1(1, 2) 执行函数体
std::cout << fun1(1, 2); // 3
double aa = 5.0;
auto fun2 = [aa]() -> double { return aa+3; }; // 此时 aa 不能进行赋值操作如:aa = 7;
std::cout << fun2(); // 8
std::cout << " aa:" << aa << std::endl; // aa:5
auto fun3 = [&aa]() -> double { aa = 7.0; return aa+3; }; // 此时 aa 以引用方式传入,可以进行赋值操作并修改外部变量 aa 的值
std::cout << fun3(); // 10
std::cout << " aa:" << aa << std::endl; // aa:7
auto fun4 = [&]() -> double { aa = 8.0; g_bb = 15; return aa+3; }; // 此时 aa 和 g_bb 都以引用方式传入
std::cout << fun4(); // 11
std::cout << " aa:" << aa << " g_bb:" << g_bb << std::endl; // aa:8 g_bb:15
}