Lambda 表达式捕获
这一节介绍 Lambda 表达式的捕获语法。首先,完整的 Lambda 表达式语法是:
[捕获] (参数列表) ->返回值类型 函数体
其中,捕获
是若干个由逗号分隔的 捕获符
。所谓的捕获符,简单来说就是要捕获的变量名。比如上一节的例子
中,n
就是一个简单的捕获符。如果要捕获多个变量,那么就是 [a, b, c]
这样。这种形式的捕获符称为复制捕获:它将局部变量复制一份,存放到 Lambda 表达式生成的匿名类的成员。此外,捕获符还可以是引用捕获。比如:
这个例子中,&n
就是引用捕获。引用捕获符的语法是 &变量名
,它的语义相当于:
即匿名类的成员 n
具有引用类型,且绑定到 main 函数中的局部变量 n
。这样,在 Lambda 表达式内对 n
修改也会影响到全局的 n
。引用捕获和复制捕获可以同时出现,比如 [&a, b]
,但不能是同一变量名。
标准不要求引用捕获必须如此实现,也可以通过指针等实现。
默认捕获符
如果有大量的局部变量需要被捕获,那手动列举出所有待捕获的变量是一件很繁琐的事。C++ 提供了默认捕获符语法,可以捕获 Lambda 表达式所在作用域内的所有名字。
[=]
是默认复制捕获符。它将当前作用域内的所有变量复制一份到匿名类的成员:
[&]
是默认引用捕获符。Lambda 表达式内可以访问和修改当前作用于内的所有变量。
默认复制捕获符后可跟随若干引用捕获符,比如 [=, &a, &b]
,此时只有 a
和 b
是引用捕获,其余变量是复制捕获。类似地,也有 [&, a, b]
等写法。
mutable
修饰
默认情形下,Lambda 表达式生成的匿名类的 operator()
是带有 const
限定的。比如,[](int a) { return a + 1; }
生成的匿名类是:
这使得 Lambda 表达式函数体内不能修改匿名类的成员,也就是不可以修改复制捕获到的变量。
为了解除这一限制,可在 Lambda 表达式中添加 mutable
修饰:
有 mutable
修饰的 Lambda 表达式,生成匿名类时不会为 operator()
添加 const
修饰。
mutable
关键字本意是修饰一些非静态成员,使得它们在整个对象为const
时仍然可以改动。比如:
其它语法
C++14 之后,捕获符还包含许多其它形式,比如带初始化器的捕获、形参包的捕获等等。它们出现的场合并不多,我就不在这里详细介绍了。有兴趣的读者可参阅 CppReference。