请考虑以下事项:
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
};
}
为什么第一个版本是编译错误,当我将lambda声明为可变并按值捕获value
时(我认为它是它的副本)?
使用clang(x86_64-apple-darwin14.3.0)测试,这是错误消息的来源,以及Visual C ++(vc120)。
答案 0 :(得分:17)
[C++11: 5.1.2/14]:
如果隐式捕获并且 capture-default 为{{1},则实体通过副本 捕获}或如果使用不包含=
的捕获显式捕获它。对于由副本捕获的每个实体,在闭包类型中声明未命名的非静态数据成员。这些成员的声明顺序未指定。 如果实体不是对象的引用,则此类数据成员的类型是相应捕获实体的类型,否则为引用类型。 [..]
lambda中&
的类型为value
,因为它是通过const int
的副本捕获的。
因此,即使lambda的调用操作符函数不是const int&
(您标记了lambda const
),实际隐式成员mutable
的类型为value
,但不能被改变了。
const int
,因为它是副本。 lambda本身上是否存在const
关键字(以及生成的调用操作符函数中是否存在mutable
关键字)应该是此处唯一的访问控制。
在C ++ 14中,您可以通过捕获const
来解决此问题,[value=value]
使用与auto
相同的规则,从而删除const
。 C ++太棒了,不是吗?
答案 1 :(得分:4)
mutable
允许lambda修改由copy捕获的非const参数的副本,但不允许它用于const
个参数。
因此,此代码有效(并输出inside 2 outside 1
):
int a = 1;
[a]() mutable {
a = 2; // compiles OK
cout << "inside " << a << "\n";
}();
cout << " outside " << a << "\n";
但如果省略mutable
或制作const int
,编译器就会出错。
在我们的例子中,第一个lambda会出错,因为value
是const
:
void test( const int &value )
如果我们copyValue
const
:
const int valueCopy = value;
然后第二个lambda会发生同样的错误。