C++ Weekly - Episode 133 脱水版: What Exactly IS A Lambda

132 阅读1分钟

C++ Weekly - Episode 133 脱水版: What Exactly IS A Lambda

Lambda 到底是什么

Lambda 实际上可以和一个可调用对象等价。参见以下几种情况:

  • 无参无捕获 lambda
// 等价于 auto lam_1 = __lambda_0();
auto lam_0 = [](){ return 5; };

struct __lambda_0
{
    auto operator()() const {
        return 5;
    }
};
  • 有参无捕获 lambda
// 等价于 auto lam_1 = __lambda_1();
auto lam_1 = [](int i){ return i + 5; };

struct __lambda_1
{
    auto operator()(int i) const {
        return i + 5;
    }
};
  • 有参有捕获 lambda
// 等价于 auto lam_3 =__lambda_3{ .__val = val};
auto lam_3 = [val](int i){ return i + val + 5; };

struct __lambda_3
{
    int __val;
    auto operator()(int i) const {
        return i + __val + 5;
    }
};

这里需要注意的是, 由于 lambda 函数默认带有 const 属性, 因此我们无法在 lambda 内部修改捕获的变量 (假如修改 val 值),否则编译器将会报错:

error: cannot assign to a variable captured by copy in a non-mutable lambda

  • mutable lambda

如果需要修改捕获变量,我们需要通过关键字 mutable 来修饰 lambda 表达式, 此时相当于移除了表达式或者可调用对象的 const 属性,如下:

// 等价于 auto lam_4 =__lambda_4{ .__val = val};
auto lam_4 = [val](int i) mutable { return i + (val++) + 5; };
    
struct __lambda_4
{
    int __val;
    auto operator()(int i) {
        return i + (__val++) + 5;
    }
};
  • 模板 lambda
// 等价于 auto lam_5 =__lambda_5{ .__val = val};
auto lam_5 = [val](auto i) { return i + val + 5; };
    
struct __lambda_5
{
    int __val;

    template<typename T>
    /* constexpr */ auto operator()(T i) const {
        return i + __val + 5;
    }
};

需要注意的一点是,C++17 开始,可调用对象会尽可能地返回 constexpr 的表达式。但是如果是捕获了局部变量,将会阻止编译器返回 constexpr.