概述:lambda表达式使用及说明
[toc]
lambda表达式说明
lambda表达式的结构如下所示:
1 | auto func = [capture] (params) opt -> ret { func_body; }; |
其中 func 是可以当作 lambda 表达式的名字,作为一个函数使用,capture 是捕获列表,params 是参数表,opt: 不需要可以省略。 (mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用 throw ()), ret 是返回值类型,func_body 是函数体。
1 | auto f = [](int a) -> int { return a + 1; }; |
使用 lambda 表达式捕获列表
lambda 表达式还可以通过捕获列表捕获一定范围内的变量:
- [] 不捕获任何变量。
- [&] 捕获外部作用域中所有变量,并作为引用在函数体中使用(按引用捕获)。
- [=] 捕获外部作用域中所有变量,并作为副本在函数体中使用(按值捕获)。
- [=,&foo] 按值捕获外部作用域中所有变量,并按引用捕获 foo 变量。
- [bar] 按值捕获 bar 变量,同时不捕获其他变量。
- [this] 捕获当前类中的 this 指针,让 lambda 表达式拥有和当前类成员函数同样的访问权限。如果已经使用了 & 或者 =,就默认添加此选项。捕获 this 的目的是可以在 lamda 中使用当前类的成员函数和成员变量。
捕获列表使用实例
1 |
|
| 函数 | 是否可读 | 是否可修改 | 说明 |
|---|---|---|---|
| x1 | ❌ | ❌ | 错误,没有捕获外部变量,不能使用任何外部变量 |
| x2 | ✔️ | ❌ | 正确,值传递,可以访问所有外部变量 |
| x3 | ✔️ | ❌ | 错误,值传递,右值可读不可修改 |
| x4 | ✔️ | ✔️ | 正确,引用传递,可读可修改 |
| x5 | ✔️ this指针的成员变量可读 ❌ 其他变量不可读 |
✔️ this指针的成员可写 ❌ 其他变量不可写 |
正确,捕获this指针,可访问this指针的成员 |
| x6 | 同 x5 |
同 x5 |
错误,捕获 this 指针,x 和 y 不是其成员变量,不可访问 |
| x7 | ✔️ 值传递三个变量,均可读 | ✔️ this指针成员可修改 ❌ x 和 y 不可修改 |
正确,捕获 this 指针,x,y |
返回值
lambda表达式的返回值通过 ‘->’ 传递,如下所示:
1 | auto add = [](int x, int y) -> int { |
如上所示的返回类型还可以使用 decltype 推导返回类型:
decltype是一个 C++ 关键字,它用于在编译时推断表达式的类型。这在编写通用代码时非常有用,特别是在使用 C++11 引入的auto关键字和范围 for 循环时。
1 | auto add = [](int x, int y) -> decltype(x+y) { |
说明:decltype(a + b) 推导了 a + b 的结果类型,并将该类型作为 lambda 函数的返回类型。
甚至,从 C++14 开始,还可以使用更简洁的方式来推导 lambda 函数的返回类型,即使用 auto 关键字。例如:
1 | auto myLambda = [](int a, int b) -> auto { return a + b; }; |
需要注意的是,使用 auto 推导返回类型的 lambda 函数在某些情况下可能会引发歧义。例如,如果你在 lambda 表达式中返回一个嵌套类型(如 std::pair),auto 可能会被推导为 std::pair,而不是你期望的嵌套类型的具体类型。在这种情况下,使用 decltype 可以更明确地指定返回类型。
其他关键字
使用 lambda 表达式捕获列表捕获外部变量,如果希望去修改按值捕获的外部变量,那么应该如何处理呢?这就需要使用 mutable 选项,被mutable修改是lambda表达式就算没有参数也要写明参数列表,并且可以去掉按值捕获的外部变量的只读(const)属性。
mutable
1 | int a = 0; |
💁♂️ 注意:mutable 只是允许在函数内部修改值而已,作用域仅限于 lambda 函数内部,参考以下代码及输出:
1 | void lambdaFunc() |
关于为什么通过值拷贝的方式捕获的外部变量是只读的:
lambda表达式的类型在C11中会被看做是一个带 operator() 的类,即仿函数。
按照C标准,lambda表达式的 operator() 默认是 const 的,一个 const 成员函数是无法修改成员变量值的。
mutable 选项的作用就在于取消 operator () 的 const 属性。
因为 lambda 表达式在 C++ 中会被看做是一个仿函数,因此可以使用std::function和std::bind来存储和操作lambda表达式:
1 | void testLambdawithfunction() |
对于没有捕获任何变量的 lambda 表达式,还可以转换成一个普通的函数指针:
1 | using func_ptr = int(*)(int); |