Lambda 按值捕获和“可变”关键字

Posted

技术标签:

【中文标题】Lambda 按值捕获和“可变”关键字【英文标题】:Lambda capture by value and the "mutable" keyword 【发布时间】:2017-06-22 17:25:23 【问题描述】:

在 lambdas 中需要关键字 mutable,这是非常混乱的根源。

考虑代码:

int x = 10;

function<void()> lambda = [=]() mutable x++; cout << "Inside lambda: x = " << x << "\n";;

cout << "Before lambda: x = " << x << "\n";
lambda();
cout << "After  lambda: x = " << x << "\n\n";

输出:

Before lambda: x = 10
Inside lambda: x = 11
After  lambda: x = 10

正如我们所见,变量 x 在 lambda 之后保持不变,因此没有副作用。

但是,如果我们“忘记”关键字 mutable,就会出现错误。

作为在 C++ 中按值传递默认值的参数,对我来说需要 mutable 关键字没有任何意义。

有人可以编写(即使是伪代码)编译器生成的类来代替 lambda 吗?

谢谢

【问题讨论】:

C++0x lambda capture by value always const?的可能重复 【参考方案1】:

如 here 所述,mutable 说明符允许 lambda 修改由复制捕获的参数并调用它们的非常量成员函数。它不会影响通过引用捕获的变量。

有人可以编写(即使是伪代码)编译器生成的类来代替 lambda 吗?

给出一般情况并不容易,但我们可以定义一些对您的具体情况有效的内容。 生成的类可能如下所示:

struct Lambda 
    void operator()()  x++; 
    int x10;
;

如果删除mutable 说明符,则函数运算符定义为const

struct Lambda 
    void operator()() const  x++; 
    int x10;
;

为简单起见,我已使用给定值 (10) 初始化 x 并将其公开,但它显然是通过使用从周围上下文捕获的变量复制初始化的,并且无法从函数运算符外部访问。 它的类型也是从用于初始化它的变量中推断出来的,就像你这样做一样:

auto lambda_x = x;

更多详情请参阅here。

【讨论】:

【参考方案2】:
class Lambda

public:
   Lambda(const Lambda&);
   ~Lambda();

   // the main functor operator, const when lambda not mutable
   R operator()(Args args) const;

   // Only present for non-capture lambda         
   operator PlainCFunctionType () const; 

   // Only present for non-capture  lambda         
   PlainCFunctionType operator+() const;
private:
   // Gets called when lambda created, but you can't call it yourself
   Lambda(Captures captures...); 

   Captures captures;
;

【讨论】:

【参考方案3】:

您并没有真正以面向对象的方式编写代码,但无论如何。 通常由 [=] 添加的外部变量是 const 值。通过添加 mutable 关键字,您可以创建它们的本地可修改副本。 您可以使用 [&] 来通过引用进行捕获。

【讨论】:

使用 [&] 改变 lambda 后的变量值。在我的代码中,捕获是按值进行的。

以上是关于Lambda 按值捕获和“可变”关键字的主要内容,如果未能解决你的问题,请参考以下文章

如何在lambda中按值捕获`this`和局部变量?

在 lambda 中,引用的按值捕获是不是会复制底层对象?

在 C++11 中按值或引用使用 lambda 默认捕获的缺点?

C ++ 0x lambda按值捕获总是const?

可变 lambda 是不是有自己的捕获值副本?

第13课 lambda表达式