Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Structured binding to replace std::tie abuse

In reading this summary of the c++17 final features I was a bit surprised by the section on structured bindings (emphasis mine):

structured bindings

Until now, there was a known trick to abuse std::tie to assign a tuple or pair to different variables directly, instead of having to deal with the result type manually. This was a hack, and also the variables had to exist, now you can declare the variables and initialize them in one line:

auto [a , b , c] = getvalues();

The braces are needed, getvalues returns a tuple. std::pair is not mentioned in the proposal, so its unclear if this works with pair, which is returned by the STL in some insert methods.

I am assuming they refer to this kind of usage of std::tie

int a,b,c;
std::tie(a,b,c) = std::make_tuple(1,2,3);

which I believed to be a recommended practice.

Can someone offer an explanation as to why they are referring to above example as a hack?

like image 485
Emerald Weapon Avatar asked Oct 25 '16 13:10

Emerald Weapon


People also ask

What is structure binding?

A structured binding declaration introduces all identifiers in the identifier-list as names in the surrounding scope and binds them to subobjects or elements of the object denoted by expression. The bindings so introduced are called structured bindings.

What is structure binding in C++?

#cpp #cpp17. Structured binding allows to initialise multiple entities by members of another object, for instance: struct stb_node { int index = 0; string value; }; stb_node node1{1, "First"}; cout << node1.

How does std :: tie work?

So basically, std::tie(a) initializes a data member reference to a . std::tuple<int>(24) creates a data member with value 24 , and the assignment assigns 24 to the data member reference in the first structure. But since that data member is a reference bound to a , that basically assigns 24 to a .


1 Answers

I can put it simply like that:

In a language where functions can return just one variable

int a,b,c;
std::tie(a,b,c) = function_returning_multiple_values();

is a hack for:

auto [a, b, c] = function_returning_multiple_values();

just as in the hypothetical world where C++ would allow just one parameter for functions

int p1, p2, p3;
p1 = ...;
p2 = ...;
p3 = ...;

function_taking_multiple_params(std::tie_params(p1, p2, p3));

would be a hack for:

function_taking_multiple_params(p1, p2, p3)

You are so accustomed with the C++ restriction that a function can return at most one object, but in fact it is just an artificial language restriction, just as a restriction to accept at most one parameter would be an artificial language restriction.

The std::tie is a library hack for a missing language feature. And it has some drawbacks:

  • the variables need be declared beforehand
  • the variable types must be declared explicitly
  • Inefficient or can't be used with types that are not default constructible

Are structured bindings everything that they could have been? No, but for the most cases they are everything we need.

What is missing?

  • Explicit type for some elements: e.g.:
auto [a, std::string b, c] = foo();

where a and c have the type deduced and b is explicit "std::string"

  • Nesting. E.g.:
auto [a, [b1, b2], c] = foo();

where the second returned object from foo is a tuple like object.

  • Language feature at the return site (bypassing std::tuple all together):
auto foo() -> [int, int]

instead of

auto foo() -> std::tuple<int, int>
  • Named return objects
auto foo() -> [int& key, int& value]

... well... wouldn't that be nice

  • and combine that with... - get ready for a cool new name - Generalized return initialization:
auto minmax_element(It begin, It end) -> [It min_it, It max_it];

auto [min = *min_it, max = *max_it] = minmax_element(...);
like image 50
bolov Avatar answered Oct 29 '22 07:10

bolov