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

时间:2017-09-08 10:20:13

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

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

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

2 个答案:

答案 0 :(得分:25)

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

P0588R1重新制定lambda捕获措辞使这一禁令明确:

  

如果lambda表达式[...]捕获结构化绑定(显式   或隐含地),该计划是不正确的。

请注意,这个措辞应该是一个占位符,而委员会确切地知道这些捕获应该如何运作。

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

这在技术上应该编译,但标准中存在一个错误。

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

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

显然,这不是一个理智的事情,委员会知道这一点,所以应该即将出现一个解决方案(尽管对于如何捕获结构化绑定应该如何工作似乎存在一些分歧。)

答案 1 :(得分:5)

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

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