How it works...

Structured bindings are a language feature that works just like std::tie(), except that we don't have to define named variables for each value that needs to be unpacked explicitly with std::tie(). With structured bindings, we define all named variables in a single definition using the auto specifier so that the compiler can infer the correct type for each variable.

To exemplify this, let's consider the case of inserting items in a std::map. The insert method returns a std::pair containing an iterator to the inserted element or the element that prevented the insertion, and a boolean indicating whether the insertion was successful or not. The following code is very explicit and the use of second or first->second makes the code harder to read because you need to constantly figure out what they represent:

    std::map<int, std::string> m; 

auto result = m.insert({ 1, "one" });
std::cout << "inserted = " << result.second << std::endl
<< "value = " << result.first->second << std::endl;

The preceding code can be made more readable with the use of std::tie, that unpacks tuples into individual objects (and works with std::pair because std::tuple has a converting assignment from std::pair):

    std::map<int, std::string> m; 
std::map<int, std::string>::iterator it;
bool inserted;

std::tie(it, inserted) = m.insert({ 1, "one" });
std::cout << "inserted = " << inserted << std::endl
<< "value = " << it->second << std::endl;

std::tie(it, inserted) = m.insert({ 1, "two" });
std::cout << "inserted = " << inserted << std::endl
<< "value = " << it->second << std::endl;

The code is not necessarily simpler because it requires defining in advance the objects that the pair is unpacked to. Similarly, the more elements the tuple has the more objects you need to define, but using named objects makes the code easier to read.

C++17 structured bindings elevate the unpacking of tuple elements into named objects to the rank of a language feature; it does not require the use of std::tie(), and objects are initialized when declared:

    std::map<int, std::string> m; 
{
auto[it, inserted] = m.insert({ 1, "one" });
std::cout << "inserted = " << inserted << std::endl
<< "value = " << it->second << std::endl;
}

{
auto[it, inserted] = m.insert({ 1, "two" });
std::cout << "inserted = " << inserted << std::endl
<< "value = " << it->second << std::endl;
}

The use of multiple blocks in the above example is necessary because variables cannot be redeclared in the same block, and structured bindings imply a declaration using the auto specifier. Therefore, if you need to make multiple calls like in the example above and use structured bindings you must either use different variable names or multiple blocks as shown above. An alternative to that is to avoid structured bindings and use std::tie(), because it can be called multiple times with the same variables, therefore you only need to declare them once.

In C++17, it is also possible to declare variables in if and switch statements with the form if(init; condition) and switch(init; condition). This could be combined with structured bindings to produce simpler code. In the following example, we attempt to insert a new value into a map. The result of the call is unpacked into two variables, it and inserted, defined in the scope of the if statement in the initialization part. The condition of the if statement is evaluated from the value of the inserted object:

    if(auto [it, inserted] = m.insert({ 1, "two" }); inserted)
{ std::cout << it->second << std::endl; }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset