Lambda表达式

用处

在面向对象中用表达式声明和定义一个函数,使其可以捕获上层函数的变量,实现闭包。或是定义只能在某个函数中使用的匿名函数

语法

1
[capture list] (parameter list) [mutable/exception/attribute] -> return type { function body }
  • capture list:捕获列表
    • 值捕获,定义时直接传值
    • 引用捕获,内部使用的是对应变量的引用
    • 隐式捕获,捕获所有外部变量,=表示值捕获,&表示引用捕获
    • 初始化捕获,捕获列表中可以定义变量,且可以自动auto
  • parameter list:传入参数列表,同普通的函数
  • [mutable/exception/attribute]:不加mutable会自动给按值捕获的变量加const
  • type:返回类型,省略后自动推导
  • function body:函数体

举例

自定义排序算法

1
sort(arr,[](int a,int b){return a>b;});

auto泛型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
int main(void){
auto f = [] (auto x) -> auto
{
if (is_integral<decltype(x)>::value)
{
return x * 2;
}
else if (is_floating_point<decltype(x)>::value)
{
return x / 2;
}
else
{
return x;
}
};
}

捕获类中的成员

1
2
3
4
5
6
class A{
int num;
void test(){
auto func = [*this](){return 2*num;};
}
}

深入浅出 C++ Lambda表达式:语法、特点和应用_c++ lamda 参数-CSDN博客

Lambda表达式虽然是一种语法糖,但它本质上也是一种函数对象,也就是重载了 operator() 的类的对象。每一个 Lambda表达式都对应一个唯一的匿名类,这个类的名称由编译器自动生成,因此我们无法直接获取或使用。Lambda表达式的捕获列表实际上是匿名类的数据成员,Lambda表达式的参数列表和返回值类型实际上是匿名类的 operator() 的参数列表和返回值类型,Lambda表达式的函数体实际上是匿名类的 operator() 的函数体。例如,下面的 Lambda表达式:

1
2
3
int x = 10;
auto f = [x] (int y) -> int { return x + y; };
12

相当于定义了一个匿名类,类似于:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int x = 10;
class __lambda_1
{
public:
__lambda_1(int x) : __x(x) {} // 构造函数,用于初始化捕获的变量
int operator() (int y) const // 重载的 operator(),用于调用 Lambda表达式
{
return __x + y; // 函数体,与 Lambda表达式的函数体相同
}
private:
int __x; // 数据成员,用于存储捕获的变量
};
auto f = __lambda_1(x); // 创建一个匿名类的对象,相当于 Lambda表达式
12345678910111213

由于 Lambda表达式是一种函数对象,因此它可以赋值给一个合适的函数指针或函数引用,也可以作为模板参数传递给一个泛型函数或类。

参考

现代 C++:Lambda 表达式 - 知乎