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 只能捕获变量。它说非元组类结构化绑定声明不会引入变量。它引入了名称,但这些名称不是变量名称。
另一方面,类似元组的结构化绑定声明确实引入了变量。 a
和 auto [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。
使用以下代码,出现编译错误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 只能捕获变量。它说非元组类结构化绑定声明不会引入变量。它引入了名称,但这些名称不是变量名称。
另一方面,类似元组的结构化绑定声明确实引入了变量。 a
和 auto [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。