为什么'mutable'是一个lambda函数属性,而不是一个捕获类型?

mmo*_*cny 41 c++ c++11

为什么c ++ 11要求我们编写:

[a,b]() mutable { a=7; } // b is needlessly mutable, potential source of bugs
Run Code Online (Sandbox Code Playgroud)

代替:

[mutable a,b]() { a=7; } // no problems here
Run Code Online (Sandbox Code Playgroud)

这是一种疏忽,被认为不够重要,还是有特定的技术原因?

Jes*_*ood 18

n2651中提到了你的建议:

可以扩展lambda表达式的语法,以允许声明闭包成员是否应该声明为可变.

这种方法可能会让程序员感到困惑,因为可变性不是闭包对象的属性,而是存储在闭包中的变量.

我不知道这是否是唯一的原因,但它似乎确实被考虑了.然而,在Herb Sutter的提议中,他建议删除mutable而不是隐含地制作捕获副本const,因此我们可能会再次看到更改.

  • @mmocny:我对这个逻辑也不是百分之百确定,但是当`mutable`应用于整个对象时,你知道在后续调用中你可能得到不同的结果.当这仅适用于成员变量时,它不像闭包对象的可变性那么清楚. (4认同)
  • 在阅读了链接论文的完整部分后,我不确定我是否完全买了这个论点(我的意思是,不仅仅是不同意,我不理解逻辑).声明是因为可变性是存储在闭包中的变量的属性,而不是闭包本身的属性,因此限制变量是混乱的,我们应该改为操作符,从而有效地改变整个闭包的可变性.关于潜在混淆的争论一般混淆;) (2认同)

Bra*_*don 6

可能是一种疏忽(与rvalue refs不能使用的方式相同),以及lambda在概念上实现的方式的工件.

int   a;
int*  b;
float c;

auto lambda1 = [&a, b, c](int d) mutable -> void {};

class lambda1 {
public:
    void operator()(int d) {}
private:
    int&  a_;
    int*  b_;
    float c_;
};

auto lambda2 = [&a, b, c](int d) -> void {};

class lambda2 {
public:
    void operator()(int d) const {}
private:
    int&  a_;
    int*  b_;
    float c_;
};
Run Code Online (Sandbox Code Playgroud)


And*_*ard 5

mutable关键字适用于lambda表达式生成的对象,而不是单独捕获的项目,因此编译器可以使用标准的第5.1.2节第5段中描述constoperator()方法使用修饰符来实现.

当且仅当lambdaexpression的parameter-declaration-clause后面没有mutable时,此函数调用运算符才被声明为const(9.3.1).

在您的示例中,lambda表达式生成的类可能如下所示:

class lambda
{
  int a, b;

public:

  lambda( int a, int b ) : a( a ), b( b ) {}

  void operator()() // non-const due to mutable keyword
  {
    a = 7;
  }
};
Run Code Online (Sandbox Code Playgroud)