99

使用以下代码,我得到一个编译错误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; }();
}();

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

4

3 回答 3

101

核心问题 2313更改了标准,因此结构化绑定永远不是变量的名称,使它们永远无法捕获。

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

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

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

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


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

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

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

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

于 2017-09-08T11:04:30.193 回答
49

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

[] {
    auto[a, b] = [] {return std::make_tuple(1, 2); }();
    auto r = [a = a] {return a; }();
}();
于 2018-01-04T21:10:48.197 回答
6

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

于 2021-11-01T02:39:31.053 回答