DEV Community

panmanio
panmanio

Posted on • Updated on • Originally published at burnicki.pl

Capture structured bindings in C++17

C++17 introduced a handy construct called structured binding:

const auto [first, second] = std::make_tuple(1,2);
Enter fullscreen mode Exit fullscreen mode

Structured bindings are used to decompose arrays and structs/classes 1 to named subobjects. Almost any object with non-static, accessible data members can be destructured this way. It works even for bit-fields:

struct BF { int x : 2; };
const auto bf (BF{1});
const auto& [y] = bf;
Enter fullscreen mode Exit fullscreen mode

Resulting aliases (first, second and y in the examples above) are actually not mere variables but rather identifiers or aliases.

This may feel unintuitive but there actually is a case when we cannot use these aliases as other variables. According to this C++ Language Standard working draft we cannot use structured bindings in lambda capture list:

If a lambda-expression explicitly captures an entity that is not odr-usable or captures a structured binding (explicitly or implicitly), the program is ill-formed.

(emphasis mine). That means following code is illegal:

auto [a, b, c] = std::make_tuple(1, 3, 7);
auto d = [b] { return b; }();
Enter fullscreen mode Exit fullscreen mode

It actually works on gcc (10.3) and msvc (v19.28) but fails on clang (12.0.0):

error: 'b' in capture list does not name a variable

This restriction does not apply for init-captures, which is reasonable as with init-captures there is a new variable defined that is captured and this variable is no longer the structured binding, so this compiles well in clang, gcc and msvc:

auto [a, b, c] = std::make_tuple(2, 7, 2);
auto d = [&b = b] { return b; }();
Enter fullscreen mode Exit fullscreen mode

The standard got reworded along the way and in C++ 20 final working draft the restriction is no longer there. But clang still fails, even with -std=c++20, while gcc and msvc are fine with both simple- and init-capture of the structured binding. I feel way more comfortable with gcc and msvc way as there is no need to provide special construct only to capture a single value.

Interesting resources:


  1. There is a difference in handling tuple-like structs and other structs. You can check this reference for more details. 

Top comments (0)