目录

lambda表达式

格式

简单使用

捕捉列表

介绍

注意

捕捉方式

其他部分

仿函数

后记-理解

补充


lambda表达式

格式

lambda表达式相当于一个匿名函数或者可调用的匿名对象,如果不把它储存在包装器等容器,那么调用一次后就销毁。


简单使用

int main() 
{ 
    //在创建lambda表达式时调用它,传入参数5和6,调用后lambda表达式销毁
    [](int x, int y)->void {cout << x + y << endl; }(5, 6);
}

结果是:

int main() 
{ 
    //将lambda储存起来,lambda的生命周期和add相同,可以多次调用
    //auto自动推导类型,此处是包装器function
    auto add = [](int x, int y)->void {cout << x + y << endl; };
    add(1,6);
    add(3,6);
}

结果是:


捕捉列表

介绍

[capture-list] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数(因此就算不捕捉变量,[]也不能省略),捕捉列表能够捕捉上下文中的变量供lambda 函数使用

注意

lambda函数默认只能使用lambda函数体内部的变量以及全局变量,比如

想要使用局部变量,需要对其进行捕捉

捕捉方式

传值捕捉

int var = 10;
int main() 
{ 
    int data1 = 5;
    int data2 = 6;
    [data1,data2](int x,int y)->void
	{
	    cout << x<< " ";
	    cout << y << " ";
	    cout << var << " ";
	    cout << data1 << " ";
	    cout << data2 << " ";
	}(1,2);
}//报错!!

程序报错!

传值捕捉本质上是一种拷贝,不影响外面的变量。捕捉到的变量无法修改只能使用,除非lambda表达式被mutable修饰符修饰(修改了也不影响外面的变量)。

传引用捕捉:

int var = 10;
int main() 
{ 
    int data1 = 5;
    int data2 = 6;
    [&data1,&data2](int x,int y)->void
	{
	    cout << x<< " ";
	    cout << y << " ";
	    cout << var << " ";
	    cout << data1 << " ";
	    cout << data2 << " ";
	    data1 = 999;
	}(1,2);
    cout << data1 << endl;
}

本质是引用,会影响外面的变量。无论是否加mutable都可以修改。

‘=’  —— 以值捕捉捕捉所有可捕捉的变量

int var = 10;
int main() 
{ 
    int data1 = 5;
    int data2 = 6;
    [=](int x,int y)->void
	{
	    cout << x<< " ";
	    cout << y << " ";
	    cout << var << " ";
	    cout << data1 << " ";
	    cout << data2 << " ";
	}(1,2);
}

‘&’  —— 以引用捕捉捕捉所有可捕捉的变量

int var = 10;
int main() 
{ 
    int data1 = 5;
    int data2 = 6;
    [&](int x,int y)->void
	{
	    cout << x<< " ";
	    cout << y << " ";
	    cout << var << " ";
	    cout << data1 << " ";
	    cout << data2 << " ";
	    data1 = 999;
	    data2 = 999;
	}(1,2);
	cout << data1 << ":" << data2 << endl;
}

传值捕捉除了data2的所有变量,只有data2是传引用捕捉

int var = 10;
int main() 
{ 
    int data1 = 5;
    int data2 = 6;
    [=,&data2](int x,int y)->void
	{
	    cout << x<< " ";
	    cout << y << " ";
	    cout << var << " ";
	    cout << data1 << " ";
	    cout << data2 << " ";
	    data1 = 999;//报错
	    data2 = 999;
	}(1,2);
	cout << data1 << ":" << data2 << endl;
}

不可以重复捕捉:


其他部分

(parameters):参数列表。

与普通函数的参数列表一致,如果不需要参数传递,则可以 连同()一起省略

mutable:修饰符。

默认情况下,lambda函数值捕捉获得的变量不能修改(即使它是副本,不会影响外界变量),加了mutable修饰符就可以在lambda函数体中修改它。本质上,mutable把仿函数类中的运算符重载的const属性去掉了,使得成员变量变得可以修改(见后记)。

使用该修饰符时,参数列表不可省略(即使参数为空)。

-> returntype:返回值类型。

没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。

{statement}:函数体。

在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。

注意:

在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空,但不能省略。因此C++11中最简单的lambda函数为:[]{}; 该lambda函数不能做任何事情

事实上,lambda的底层与仿函数,即函数对象很相似,lambda捕捉到的变量就是以成员变量的方式存储的,捕捉的本质是用构造函数初始化。


仿函数

仿函数就是重载()运算符的类的对象,使对象可以像函数一样调用

举个例子:

class Compare 
{
public:
    bool operator()(int x,int y) 
    {
        return x > y;
    }
};
int main() 
{
    Compare compare;
    cout<<compare(1,2)<<endl;//像函数一样调用它
}

后记-理解

编译器遇到lambda表达式本质上会做几件事:

创建一个仿函数类,该类重载了()运算符,()运算符重载内部就是lambda表达式的函数体。

把捕捉到的变量在仿函数类中用成员变量表示。

创建一个仿函数类的临时对象并()调用。

// 你写的Lambda
int x = 10;
auto mylambda = [x]() { return x + 1; };

// 编译器大致生成的代码
class __AnonymousLambda {
private:
    int x;  // 捕获的变量成为成员变量
public:
    __AnonymousLambda(int _x) : x(_x) {}  // 构造函数初始化捕获的变量
    int operator()() const { return x + 1; }  // 函数调用运算符
};

__AnonymousLambda mylambda(x);  // 实际上mylambda就是__AnonymousLambda构造出来的对象

补充

mutable除了上述在lambda中的作用,还有一个作用就是用于修饰类内的非静态成员变量,表示即使被const修饰的成员函数也可以修改指定的成员变量。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐