Thr*_*r57 33 c++ lambda c++17 structured-bindings visual-studio-2017
使用以下代码,我得到一个编译错误C2065 'a': undeclared identifier(使用Visual Studio 2017):
[] {
auto [a, b] = [] {return std::make_tuple(1, 2); }();
auto r = [&] {return a; }(); //error C2065
}();
Run Code Online (Sandbox Code Playgroud)
但是,以下代码编译:
[] {
int a, b;
std::tie(a, b) = [] {return std::make_tuple(1, 2); }();
auto r = [&] {return a; }();
}();
Run Code Online (Sandbox Code Playgroud)
我以为这两个样本是等价的.它是编译器错误还是我错过了什么?
T.C*_*.C. 43
核心问题2313改变了标准,因此结构化绑定永远不是变量的名称,使它们永远不可捕获.
P0588R1对lambda捕获措辞的重新制定使这一禁令明确:
如果lambda-expression [...]捕获结构化绑定(显式或隐式),则程序格式错误.
请注意,这个措辞应该是一个占位符,而委员会确切地指出这些捕获应该如何工作.
以前的答案保留了历史原因:
这在技术上应该编译,但这里的标准有一个错误.
标准说lambdas只能捕获变量.并且它表示非类似元组的结构化绑定声明不会引入变量.它引入了名称,但这些名称不是变量的名称.
另一方面,类似元组的结构化绑定声明确实引入了变量.a和bin auto [a, b] = std::make_tuple(1, 2);是实际的引用类型变量.所以他们可以被lambda捕获.
显然这不是一个理智的事情,委员会知道这一点,所以应该即将出现修复(虽然对于如何捕获结构化绑定应该如何工作似乎存在一些分歧).
aka*_*n64 11
可能的解决方法是使用初始化程序的lambda捕获.以下代码在Visual Studio 2017 15.5中编译良好.
[] {
auto[a, b] = [] {return std::make_tuple(1, 2); }();
auto r = [a = a] {return a; }();
}();
Run Code Online (Sandbox Code Playgroud)
您可以像这样使用 init-capture ,如https://burnicki.pl/en/2021/04/19/capture-structured-bindings.html中的建议。该变量是通过引用捕获的,因此没有开销,也不需要处理指针。
auto [a, b] = [] { return std::make_tuple(1, 2); }();
auto r = [&a = a] { return a; }();
Run Code Online (Sandbox Code Playgroud)
对结构化绑定及其引用使用相同的名称可能会产生误导,但实际上这意味着
auto r = [&a_ref = a] { return a_ref; }();
Run Code Online (Sandbox Code Playgroud)
据我所知,它适用于从 C++17 及更高版本开始的所有编译器,包括 clang。