【问题标题】:lambda capture by value mutable doesn't work with const &?通过值可变捕获的 lambda 不适用于 const &?
【发布时间】:2015-10-07 17:15:17
【问题描述】:

考虑以下几点:

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) 进行测试。

【问题讨论】:

  • GCC 主干也是(“错误:分配只读变量‘值’”)
  • 源变量的const-ness 似乎胜过lambda 的mutable-ness。将其更改为[value=value] 可以解决 gcc 中的错误。

标签: c++ c++11 lambda


【解决方案1】:

[C++11: 5.1.2/14]: 如果实体被隐式捕获并且 capture-default=,则它被副本捕获 >如果它是使用不包含& 的捕获明确捕获的。对于通过副本捕获的每个实体,在闭包类型中声明了一个未命名的非静态数据成员。这些成员的声明顺序是未指定的。 如果实体不是对对象的引用,则此类数据成员的类型为相应捕获实体的类型,否则为引用类型。 [..]

您的 lambda 中 value 的类型是 const int,因为它是通过从 const int& 复制捕获的。

因此,即使 lambda 的调用运算符函数不是 const(您将 lambda 标记为 mutable),实际的隐式成员 value 的类型为 const int,并且不能被变异。

坦率地说,这似乎很荒谬;我希望这条规则说引用的类型会丢失constness,因为它是一个副本。 lambda 本身是否存在mutable 关键字(因此,生成的调用运算符函数上是否存在const 关键字)应该是这里唯一的访问控制。

在 C++14 中,您可以通过捕获为 [value=value] 来解决此问题,它使用与 auto 相同的规则,因此删除了 const。 C++ 很棒,不是吗?

【讨论】:

  • 这不会覆盖调用者的假设/意图吗?
  • @underscore_d:调用者写了mutable。在我看来,这个意图很明确,而这让成员本身const 太过分了。
  • 是的,现在我已经醒来并注意到它被价值捕获,我明白你的意思了。这看起来只是章鱼有太多腿引入的另一种歧义......
  • C++14 在这方面的规则看起来要复杂得多。他们可以通过[value=value] 修复它,Drew 建议至少修复 GCC 中的问题。我还没有深入研究。
  • 是的,init-capture 丢失了 const,因为它使用 auto 的规则。我认为简单的按值捕获的 const-preserving-ness 是设计使然。
【解决方案2】:

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";

但是如果我们省略mutable,或者创建一个const int,编译器就会报错。

在我们的例子中,第一个 lambda 会给出错误,因为 valueconst

void test( const int &value )

如果我们让copyValue const:

const int valueCopy = value;

那么第二个 lambda 也会出现同样的错误。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    • 2018-11-19
    • 1970-01-01
    • 2019-08-28
    • 2013-11-06
    相关资源
    最近更新 更多