【问题标题】:"Capture by move" does not prevent capture by reference“通过移动捕获”不会阻止通过引用捕获
【发布时间】:2021-04-07 14:13:51
【问题描述】:

当我写[&,x](){ /* making use of x */ }时,x被值捕获。

当我写[=,&x](){ /* making use of x */ } 时,x 被引用捕获。

如果我尝试编写 [&x, x](){ … },我收到一条错误消息,告诉我 x 只能在捕获列表中出现一次。

但是,[&x, y = std::move(x)](){ /* making use of x and y */ }(); 可以正常编译,但出现分段错误。

为什么代码甚至可以编译?为什么标准允许我通过引用捕获变量,并且我还在“通过移动捕获”初始化捕获中使用它?

【问题讨论】:

  • “但我遇到了分段错误。”。这是由于 lambda 的主体不正确。因为您似乎错误地使用了已移动的x
  • “一个错误告诉我 x 只能在捕获列表中出现一次” - 很难将有关 init-capture 的所有约束都放入一个简洁的错误消息中。重要的是要记住捕获的哪些部分被转换为闭包的成员。我们不能有两个同名的不同成员。这就是“必须出现一次”的上下文。
  • @Jarod42,这就是我的观点。我可以(错误地)在正文中使用x,因为我通过引用捕获它,除了将它移动到y
  • @StoryTeller-UnslanderMonica,我认为您的评论可能是一个很好的答案。
  • rust 不允许使用从对象移动,C++ 允许,你甚至可能有有效的情况。另请注意,auto y = std::move(x); auto lambda = [&x, &y](){/*..*/}; 的行为与您的相似。

标签: c++ c++11 lambda c++14


【解决方案1】:

[&x, y = std::move(x)](){ }; 的情况从编译器的角度来看是非常合法的,因为捕获时使用了不同的标识符。标准规定如下:

[expr.prim.lambda/capture-2]

忽略 init-capturesinitializers 中的出现,标识符或 this 不得在 lambda- 中出现多次捕获

[&i, a = i]{ };    // OK
[&i, a = std::move(i)]{ };    // OK

[&i, i]{ };       // error: i repeat
[&i, i = std::move(i)]{ };    // error: i repeated

【讨论】:

    猜你喜欢
    • 2016-02-08
    • 1970-01-01
    • 1970-01-01
    • 2014-02-09
    • 2019-08-28
    • 1970-01-01
    • 2020-01-23
    • 2018-01-04
    • 1970-01-01
    相关资源
    最近更新 更多