Lambda表达式

发布于:2024-12-18 ⋅ 阅读:(122) ⋅ 点赞:(0)

C++ Lambda表达式

Lambda 表达式是一种匿名函数,可以在代码中直接定义并使用。它主要用于简化那些只需要简单操作的函数定义。在 C++ 中,lambda 表达式的语法结构通常包括以下几个部分:

  1. 捕获列表:定义 lambda 表达式如何访问外部变量。
  2. 参数列表:定义传递给 lambda 表达式的参数。
  3. opt 选项: 不需要可以省略
    1. mutable: 可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)
    2. exception: 指定函数抛出的异常,如抛出整数类型的异常,可以使用throw();
  4. 可选的返回类型说明:指定 lambda 表达式的返回类型。
  5. 函数体:包含执行的具体代码。

基本用法

[capture-list] (parameters) opt -> return-type {
    function-body
}

捕获列表

Lambda 表达式的捕获列表可以捕获一定范围内的变量,具体使用方式如下:

  1. [] - 不捕获任何变量
  2. [&] - 捕获外部作用域中所有变量,并作为引用在函数体内使用(按引用捕获)
  3. [=] - 捕获外部作用域中所有变量,并作为副本在函数体内使用(按值捕获)
    1. 拷贝的副本在匿名函数体内部是只读的
  4. [=, &foo] - 按值捕获外部作用域中所有变量,并按照引用捕获外部变量 foo
  5. [bar] - 按值捕获 bar 变量,同时不捕获其他变量
  6. [&bar] - 按引用捕获 bar 变量,同时不捕获其他变量
  7. [this] - 捕获当前类中的 this 指针
    1. 让 Lambda 表达式拥有和当前类成员函数同样的访问权限
    2. 如果已经使用了 & 或者 =,默认添加此选项

下面通过一个例子,看一下捕获列表的具体用法:

class Test
{
public:
    void output(int x, int y)
    {
        auto x2 = [=] {
            x = 1;
            return m_number + x + y; 
        };             // error x 必修是可修改的左值
        auto x3 = [&] {
              x = 1;
            return m_number + x + y; 
        };             // ok
        auto x4 = [this] {
            x = 1;
            return m_number; };                  // error x 必修是可修改的左值
        auto x5 = [this] {
            x = 1;
            return m_number + x + y; };          // error x 必修是可修改的左值
        auto x6 = [this, x, y] {
            x = 1;    
            y = 2;
            return  m_number + x + y;  // error x 必修是可修改的左值
        };    // ok
        auto x7 = [this,&x] {
            x = 1;
            return m_number++; };                // ok
    }
    int m_number = 100;
};

💡 在匿名函数内部,需要通过lambda表达式的捕获列表控制如何捕获外部变量,以及访问哪些变量。默认状态下lambda表达式无法修改通过复制方式捕获外部变量,如果希望修改这些外部变量,需要通过引用的方式进行捕获。

返回值

很多时候,lambda表达式的返回值是非常明显的,因此在C++11中允许省略lambda表达式的返回值。

// 完整的lambda表达式定义
auto f = [](int a) -> int
{
    return a+10;  
};

// 忽略返回值的lambda表达式定义
auto f = [](int a)
{
    return a+10;  
};

一般情况下,不指定lambda表达式的返回值,编译器会根据return语句自动推导返回值的类型,但需要注意的是labmda表达式不能通过列表初始化自动推导出返回值类型。

// ok,可以自动推导出返回值类型
auto f = [](int i)
{
    return i;
}

// error,不能推导出返回值类型
auto f1 = []()
{
    return {1, 2};	// 基于列表初始化推导返回值,错误
}
// ok,可以自动推导出返回值类型
auto f = [](int i)
{
    return i;
}

// error,不能推导出返回值类型
auto f1 = []()
{
    return {1, 2};	// 基于列表初始化推导返回值,错误
}

mutable

使用lambda表达式捕获列表捕获外部变量,如果希望去修改按值捕获的外部变量,那么应该如何处理呢?这就需要使用mutable选项,被mutable修改是lambda表达式就算没有参数也要写明参数列表,并且可以去掉按值捕获的外部变量的只读(const)属性。

int a = 0;
auto f1 = [=] {return a++; };              // error, 按值捕获外部变量, a是只读的
auto f2 = [=]()mutable {return a++; };     // ok

网站公告

今日签到

点亮在社区的每一天
去签到