Lambda implicit capture fails with variable declared from structured binding

C++LambdaVisual Studio-2017C++17Structured Bindings

C++ Problem Overview


With the following code, I get a compile error C2065 'a': undeclared identifier (using visual studio 2017):

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

However, the following code compiles:

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

I thought that the two samples were equivalent. Is it a compiler bug or am I missing something ?

C++ Solutions


Solution 1 - C++

Core issue 2313 changed the standard so that structured bindings are never names of variables, making them never capturable.

P0588R1's reformulation of lambda capture wording makes this prohibition explicit:

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

Note that this wording is supposedly a placeholder while the committee figures out exactly how such captures should work.

Previous answer kept for historical reasons:


This technically should compile, but there's a bug in the standard here.

The standard says that lambdas can only capture variables. And it says that a non-tuple-like structured binding declaration doesn't introduce variables. It introduces names, but those names aren't names of variables.

A tuple-like structured binding declaration, on the other hand, does introduce variables. a and b in auto [a, b] = std::make_tuple(1, 2); are actual reference-typed variables. So they can be captured by a lambda.

Obviously this is not a sane state of affairs, and the committee knows this, so a fix should be forthcoming (though there appears be some disagreement over exactly how capturing a structured binding should work).

Solution 2 - C++

A possible workaround is to use a lambda capture with the initializer. The following code compiles fine in Visual Studio 2017 15.5.

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

Solution 3 - C++

Now lambda could capture structured binding since c++20, see this.

Recommended Structured Bindings Solutions

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThreeStarProgrammer57View Question on Stackoverflow
Solution 1 - C++T.C.View Answer on Stackoverflow
Solution 2 - C++akarin64View Answer on Stackoverflow
Solution 3 - C++Kai GuView Answer on Stackoverflow