C++中的Lambda表达式详解
简介:
Lambda表达式(又称Lambda函数,英文原文是Lambda Expression),是C++11的新特性中非常实用的一个。
按照cppreference的官方中文解释,
构造一个闭包:能在作用域内捕获变量一个的匿名函数对象。
一个常见的Lambda表达式的结构如下(省略了mutable、exception、attribute和-> ret):
[ 捕获 ] ( 参数列表 ) { 函数体 }
例如:
[](int a, int b) -> int { return a + b; };
除了[]是Lambda表达式特有的,后面的参数列表、函数体是和普通命名函数一样的。那捕获是什么意思该怎么写呢?
[&]表示以引用形式捕获当前作用域的全部自动储存持续性变量
[=]表示以传值形式捕获当前作用域的全部自动储存持续性变量
[a, &b]以传值形式捕获变量a,以引用形式捕获变量b
[a, &]以传值形式捕获变量a,以引用形式捕获当前作用域其它的自动储存持续性变量
[this]以传值形式捕获this指针
[]什么也不捕获
// 定义一个简单的lambda表达式
auto basicLamda = [] {cout << "hello world!" << endl; };
basicLamda(); // 调用
// 如果需要参数,那么就要像函数那样,放在圆括号里面,如果有返回值,返回类型要放在->后面,即拖尾返回类型
// 当然你也可以忽略返回类型,lambda会帮你自动推断出返回类型
auto add = [](int a, int b) -> int {return a + b; };
int result = add(4, 5);
cout << "result = " << result << endl;
// 自动推断出返回类型
auto multiply = [](int a, int b) {return a * b; };
int result1 = multiply(5, 6);
cout << "result1 = " << result1 << endl;
对于[=]或[&]的形式,lambda表达式可以直接使用this指针。但是,对于[]的形式,如果要使用this指针,必须显式传入:this { this->someFunc(); }();
class Test{
public:
void hello(){
cout << "test hello!\n";
};
void lambda(){
auto fun = [this]{ // 捕获了 this 指针
this->hello();
}; // 这里 this 调用的就是 class Test 的对象了
fun();
}
};
所谓传值(value)还是引用(reference)和命名函数中一样,引用传递的参数在Lambda表达式的函数体中被修改后,原作用域的变量也会发生变化,而传值的变量则会被作为只读变量供Lambda表达式函数体来使用,Lambda表达式的函数体无法修改该变量(加上mutable关键词可以修改,但是修改的结果不会影响到原作用域)。
#include <iostream>
#include <functional>
#include <algorithm>
using namespace std;
int main ()
{
int a = 10, b = 10;
function<void (void)> func1 = [a] () mutable { cout << ++a << endl; };
function<void (void)> func2 = [&b] () { cout << ++b << endl; };
func1();
func2();
cout << "a: " << a << "\nb: " << b << endl;
return 0;
}
上述代码的输出:
11
11
a: 10
b: 11
可以看到,虽然有mutable关键词,在func1函数体内部也被修改了,但是在原作用域(即main中),a并没有被修改,因为a是通过传值捕获的变量。而b成功被修改了,因为b是引用捕获的。如果去掉mutable关键词,这段代码在编译时就会报错,因为默认传值捕获的变量是只读的(相当于常量),不可以被修改。
lamdba表达式这部分的内容应该不难,编程的学习,其实还是如同英语的学习都一样,了解语法后,然后多练习debug 加深理解。同时对照一些必要的参考手册,教材。本篇内容的参考可以阅读:[Lambda函数],(https://zh.cppreference.com/w/cpp/language/lambda)