考虑以下:
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++很棒,不是吗?
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 也会发生同样的错误。
| 归档时间: |
|
| 查看次数: |
3933 次 |
| 最近记录: |