Lambda 隐式捕获因从结构化绑定声明的变量而失败

Lambda implicit capture fails with variable declared from structured binding

使用以下代码,出现编译错误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; }();
}();

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

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

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

If a lambda-expression [...] captures a structured binding (explicitly or implicitly), the program is ill-formed.

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

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


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

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

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

显然这不是一个理智的事态,委员会知道这一点,因此应该会尽快修复(尽管对于捕获结构化绑定应该如何工作似乎存在一些分歧)。

一种可能的解决方法是对初始化程序使用 lambda 捕获。以下代码在 Visual Studio 2017 15.5.

中编译良好
[] {
    auto[a, b] = [] {return std::make_tuple(1, 2); }();
    auto r = [a = a] {return a; }();
}();

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