-
(1)为什么要引入
lambda表达式?
因为其他语言有,C++不想落后。正经的说,lambda表达式其实就是一个匿名函数对象。重点在这个匿名上,当我们需要一个函数,但是这个函数使用的次数很少,一到两次,我们不想费心思去为它想一个合适的名字,此时,匿名函数是一个很好的选择。 -
(2)什么是闭包?
wiki的解释为 在计算机科学中,闭包(英语:Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures),是引用了自由变量的函数。这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。所以,有另一种说法认为闭包是由函数和与其相关的引用环境组合而成的实体。闭包在运行时可以有多个实例,不同的引用环境和相同的函数组合可以产生不同的实例。
官方对lambda的定义为:能够捕获作用域中的变量的无名函数对象。 -
(3)lambda表达式
[ 捕获 ] ( 形参 ) 说明符(可选) 异常说明 attr -> ret { 函数体 } (1)
这是对于lambda表达式一个完整的声明 。举个例子
#include <iostream>
#include <string>
int main()
{
std::string hello = "hello";
auto hello_func = [hello](std::string name) mutable noexcept /*[[attr]]*/ -> void {std::cout << hello << ", " << name << "\n"; };
hello_func("Leo");
hello_func("Fan");
return 0;
}
hello_func 是我们声明的一个匿名函数对象,它是可被调用的。
[hello](std::string name) mutable noexcept /*[[deprecated]]*/ -> void {std::cout << hello << ", " << name << "\n"; };
是一个lambda表达式,它的求值结果是一个匿名函数对象。这个lambda表达式的结构有些复杂,事实上,我们可以简化lambda表达式,最简形式为:[ 捕获 ] { 函数体 }
[hello]表示该lambda表达式捕获了hello这个变量。我们这里来讲一下捕获(capture)
- 若变量满足下列条件,则 lambda 表达式可以不捕获就使用它
1.1 该变量为非局部变量,或具有静态或线程局部存储期(该情况下无法捕获该变量),或者
1.2 该变量为以常量表达式初始化的引用。 - 若变量满足下列条件,则 lambda 表达式可以不捕获就读取其值
2.1 该变量具有 const 而非 volatile 的整型或枚举类型,并已用常量表达式初始化,或者
2.2 该变量为 constexpr 且无 mutable 成员。
(std::string name) 是形参列表。 如果在形参列表里使用auto来声明变量,那么该lambda表达式为generic lambda。我们可以简单的把这个形参列表理解为函数的形参列表,并没有啥不同。
mutable是函数的说明符,这个不是必须的。mutable在这里的意思是可以修改通过值捕获的变量,并调用它们的non-const函数。除此之外还有constexpr(C++ 17) 和consteval(C++ 20)。
noexcept为异常说明,其在这里的意思等价于noexcept(true)和throw(),即不抛出异常。
[[attr]]这里本来是放置属性的,这里的属性是给closureType,而不是给lambda的表达式的。我没有找到一个合适的属性,所以就简单的注释掉了。尴尬
->void表明返回类型。如果不写的话返回值类型能被自动的推导出来。
std::cout << hello << ", " << name << "\n"; }为函数体。
lambda表达式为纯右值表达式。它的类型为ClosureType,是无名的,非联合的,非聚合的类型。







网友评论