【问题标题】:Lambda implicit capture fails with variable declared from structured bindingLambda 隐式捕获因结构化绑定声明的变量而失败
【发布时间】:2018-02-17 05:54:59
【问题描述】:

使用以下代码,我得到一个编译错误C2065 'a': undeclared identifier(使用 Visual Studio 2017):

[] {
    auto [a, b] = [] {return std::make_tuple(1, 2); }();
    auto r = [&] {return a; }(); //error C2065
}();

但是,以下代码编译:

[] {
    int a, b;
    std::tie(a, b) = [] {return std::make_tuple(1, 2); }();
    auto r = [&] {return a; }();
}();

我认为这两个样本是等价的。是编译器错误还是我遗漏了什么?

【问题讨论】:

  • gcc 8.1.1 编译没有抱怨。 clang 6.0.1 报错。
  • AFAICS,事实上(我也可以证明)这在-std=c++17 模式下现在可以在g++ 8 中工作,这意味着(A)某些修复已被视为缺陷并向后移植,其中我找不到任何直接的迹象,或者 (B) g++ 可能允许它作为扩展,甚至是无意的。
  • C++20 允许捕获结构化绑定(如果按值单独复制它们)。
  • @ThreeStarProgrammer57: Yes;请注意,此处引入的通过引用捕获它们的限制后来被删除(在进一步分析确定不需要其他更改来正确支持它们之后)。

标签: c++ lambda visual-studio-2017 c++17 structured-bindings


【解决方案1】:

Core issue 2313 更改了标准,使得结构化绑定永远不会是变量的名称,从而使它们永远无法捕获。

P0588R1 对 lambda 捕获措辞的重新表述明确了这一禁令:

如果 lambda 表达式 [...] 捕获结构化绑定(显式 或隐含地),程序格式错误。

请注意,这个措辞应该是一个占位符,而委员会会弄清楚这种捕获应该如何工作。

由于历史原因保留了以前的答案:


这在技术上应该可以编译,但是这里的标准中有一个错误。

标准规定 lambda 只能捕获变量。它说非元组的结构化绑定声明不会引入变量。它引入了名称,但这些名称不是变量的名称。

另一方面,类似元组的结构化绑定声明确实引入了变量。 auto [a, b] = std::make_tuple(1, 2); 中的 ab 是实际的 引用类型的变量。所以它们可以被 lambda 捕获。

显然,这不是一个理智的状态,委员会知道这一点,因此应该会尽快修复(尽管在捕获结构化绑定的确切方式上似乎存在一些分歧)。

【讨论】:

  • 友情提醒,此问题已解决。目前,类似元组的结构化绑定引入了唯一名称的变量,ab 命名了这些变量引用的 glvalues。
  • 有一篇论文正在筹备中,可以改变这一点,但工作论文还没有发生任何事情,所以没有什么需要更新的。
  • 我的每一句话:WTF ??
  • C++20 有什么变化吗? GCC 现在允许您从结构化绑定中捕获变量,而 clang 不允许。哪个编译器是正确的?
  • 另一方面,类似元组的结构化绑定声明确实引入了变量。 Clang 12 仍然不接受它:gcc.godbolt.org/z/9zc8o3scT
【解决方案2】:

一种可能的解决方法是使用带有初始化程序的 lambda 捕获。以下代码在 Visual Studio 2017 15.5 中编译良好。

[] {
    auto[a, b] = [] {return std::make_tuple(1, 2); }();
    auto r = [a = a] {return a; }();
}();

【讨论】:

  • 惊呆了?。这就像作为 neo 捕获列表的 python lambda 默认参数。注意:你的东西也可以在 clang 中工作(这是整个问题中唯一的吠叫编译器)godbolt.org/z/PcAZNG
  • 虽然请注意这更像是“按价值捕获”。
【解决方案3】:

现在 lambda 可以捕获自 c++20 以来的结构化绑定,请参阅 this

【讨论】:

  • 很好,谢谢,如果您有机会将标准中的相关部分链接起来会很棒。
  • 我猜是从 C++17 开始的?
  • @Silviu,这个链接指出“结构化绑定不能被 lambda 表达式捕获。(直到 C++20)”
猜你喜欢
  • 1970-01-01
  • 2012-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多