值可变的lambda捕获不适用于const&?

ric*_*h.e 13 c++ lambda c++11

考虑以下:

void test( const int &value )
{
    auto testConstRefMutableCopy = [value] () mutable {
        value = 2; // compile error: Cannot assign to a variable captured by copy in a non-mutable lambda
    };

    int valueCopy = value;
    auto testCopyMutableCopy = [valueCopy] () mutable {
        valueCopy = 2; // compiles OK
    };
}
Run Code Online (Sandbox Code Playgroud)

当我将lambda声明为可变并按value值捕获时(为什么我认为它是副本),为什么第一个版本是编译错误?

使用clang(x86_64-apple-darwin14.3.0)进行测试,这是错误消息的来源,以及Visual C++(vc120).

Lig*_*ica 17

[C++11: 5.1.2/14]: 如果实体被隐式捕获并且捕获默认值为=或者如果使用不包含的捕获显式捕获&实体,则通过副本捕获实体.对于由副本捕获的每个实体,在闭包类型中声明未命名的非静态数据成员.这些成员的声明顺序未指定.如果实体不是对对象的引用,则这种数据成员的类型是对应的捕获实体的类型,否则是引用的类型. [..]

valuelambda内部的类型是const int,因为它是从一个副本中捕获的const int&.

因此,即使lambda的调用操作符函数不是const(您标记为lambda mutable),实际的隐式成员value也是类型const int且不能变异.

坦率地说,这似乎很荒谬; 我希望这条规则可以说引用的类型失去了const,因为它是一个副本.mutablelambda本身上是否存在关键字(因此,const生成的调用操作符函数中是否存在关键字)应该是此处唯一的访问控制.

在C++ 14中,你可以通过捕获as来解决这个问题[value=value],它使用与之相同的规则auto,从而删除了const.C++很棒,不是吗?


Ale*_*exD 5

mutable允许 lambda 修改由 copy 捕获的非常量参数的副本,但不允许对const参数进行修改。

所以这段代码可以工作(并输出inside 2 outside 1):

int a = 1;
[a]() mutable {
    a = 2; // compiles OK
    cout << "inside " << a << "\n";
}();
cout << " outside " << a << "\n";
Run Code Online (Sandbox Code Playgroud)

但如果我们省略mutable或创建const int,编译器会给出错误。

在我们的例子中,第一个 lambda 给出了一个错误,value因为const

void test( const int &value )
Run Code Online (Sandbox Code Playgroud)

如果我们做copyValue const

const int valueCopy = value;
Run Code Online (Sandbox Code Playgroud)

那么第二个 lambda 也会发生同样的错误。