If a function returns two or three closely associated values, then the caller has to be willing to accept them as a single object. Structured bindings allow this object to be destructured in a single step into appropriately named variables.
The simplest example unpacks a pair, std::pair.
#include <iostream>
#include <utility>
int main()
{
// Group these two values into one pair
std::pair<int, double> p{ 10, 3.14 };
auto [i, d] = p;
std::cout << i << ' ' << d << '\n';
}
Here, the pair p contains an integer and a double. The binding auto [i, d] = p declares two variables and initializes them to hold copied values from p.first and p.second, respectively. The following line prints out the contents. You have ordinary variables i and d at this point, which you can use independently of p.
This is just as easy for a std::tuple containing an arbitrary number of elements.
#include <iostream>
#include <tuple>
int main()
{
// Store several differently typed values in one tuple
std::tuple<int, double, char> t{ 5, 1.5, 'x' };
auto [a, b, c] = t;
std::cout << a << ' ' << b << ' ' << c << '\n';
}
The tuple t contains three values, and the binding auto [a, b, c] = t declares three local variables which are initialized with copies of the values from the tuple, in order. The final line prints them all. This requires, as you'd expect, that the number of names within the brackets must match the number of values in the object they're bound to exactly. Otherwise, it's a compile time error.
Ordinary arrays are unpacked in exactly the same way.
#include <iostream>
int main()
{
int arr[3]{ 7, 8, 9 };
// Let the initializer determine this variable type
auto [x, y, z] = arr;
std::cout << x << ' ' << y << ' ' << z << '\n';
}
We have an array of three ints, and this statement declares three int variables x, y, and z which get initialized with the array elements. Those elements are then printed. The array itself is left unmodified.
And it's possible for an ordinary C style struct to be unpacked as well.
#include <iostream>
// Define the members that belong to this type
struct Point
{
int x;
int y;
};
int main()
{
Point p{ 4, 2 };
auto [a, b] = p;
std::cout << a << ' ' << b << '\n';
}
The Point struct with its two public members is destructured into two local variables named by the elements it's bound to. The printed output is the two values stored in the structure. These are also bound by declaration order.
In all cases, the names used in the bound object are new variables that are initialized to their components and have an independent lifetime; the original object is never modified by the binding operation itself, unless binding to references, which is another topic.
So structured bindings turn an object containing one or two pieces of information into a set of named variables, making your code shorter and cleaner.
0 comments
No comments yet. Be the first.