Dominik Berner

Unpacking a fixed-size container in C++ can be tedious, and require you to fiddle around with std::get or std::tie. But not anymore, thanks to the new structured bindings introduced in C++17. Unpacking anything with a fixed size into named variables never has been easier.

Structured bindings provide a syntax without boilerplate to allow unpacking any data structure whose size is known during compile time. And yes even works with structs and public members of classes.

Structured bindings always have to be declared using auto and may have all the possible decorations like const or reference (&). This removes the possibility of explicitly casting the data into a different or more specific data type than what is known at compile time. But as explicit casting should generally be avoided as often as possible, this limitation rather helps writing strongly typed code than being a hindrance. All bindings have the same const-ness and are all either copied or referenced, which means partially mutable access to a data structure is also ruled out.

Extracting classes and structs is, as mentioned, possible but has a few possible pitfalls.

While this works as expected there is a word of warning here, that unpacking depends obviously on the order of declaration in the class or struct. As long as this order is tightly controlled this is not so much a problem, but since the members of a struct are already named they are often not associated with positional stability. Experience shows that during refactoring class members often get regrouped semantically in a header file, which in that case could prove a disaster for any code using the structured bindings.

A much better approach when working with classesand structs is to add support for structured bindings, which is quite easy, by template-specializing std::tuple_size, std::tuple_element and get. By the way, this pairs nicely with if constexpr, another feature introduced in C++17. Specializing a class in this way removes the dependency on the order of the declaration and also allows to change the return type of the parameter returned or return additional information as a positional parameter.

A side note is that so far structured bindings do not cover partial extraction as was possible with std::tieand std::ignore, so one has to create dummy variables if only interested in parts of a tuple. However, due the guaranteed copy elision introduced in c++17, this should be side-effect free if compiled with any kind of compile-time optimization enabled.

To conclude one can say that structured bindings are a nice way to lighten the syntax of handling and extracting fixed size containers, without the need to fiddle with templates. They are the linear “evolution” of auto and help bring datatypes like std::tuple or std::array more naturally into the code.

This post was last modified on December 11, 2024 9:50 am