In reading this summary of the c++17 final features I was a bit surprised by the section on structured bindings (emphasis mine):
structured bindi
std::tie
in itself has another functionality.
It was meant for creating a tuple with references to variables
Creates a tuple of lvalue references to its arguments or instances of std::ignore.
This is useful for creating on-the-fly tuples without having to copy the variables because they are references. I just take the example from cppreference for a usecase.
bool operator<(const S& rhs) const
{
// compares n to rhs.n,
// then s to rhs.s,
// then d to rhs.d
return std::tie(n, s, d) < std::tie(rhs.n, rhs.s, rhs.d);
}
Here tuples are created but they don't copy the variables but have references.
Now because they hold references you could "hack" it to do something like this
int a,b,c;
std::tie(a,b,c) = std::make_tuple(1,2,3);
It assigns the values of the returned tuple to the one with the references in itself.
This is even on cpprefence just mentioned as a "note"
std::tie may be used to unpack a std::pair because std::tuple has a converting assignment from pairs
In c++17 they introduced "structured bindings" to take care of the scenario to assign multible variables at once. So whether it was intentional or a hack, since c++17 this usage of tie should not be necessary anymore.
Whether std::tie
was meant to be used that way or is a "hack" may be personal opinion, I guess the people who introduced std::tie
know best for this. But considering how structured binding kind of replaces std::tie
in that instance, they came up with a solution they think is better.
A very noticeable difference is std::ignore. Look at the example
std::tuple<string, string> data {"Lord", "Buddha"};
auto [a, b] = data; //valid
auto [ , b] = data; //not valid as the identifier is strongly required
string y;
std::tie( std::ignore, y ) = data; //voila
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:
Are structured bindings everything that they could have been? No, but for the most cases they are everything we need.
What is missing?
auto [a, std::string b, c] = foo();
where a
and c
have the type deduced and b
is explicit "std::string"
auto [a, [b1, b2], c] = foo();
where the second returned object from foo
is a tuple
like object.
std::tuple
all together):auto foo() -> [int, int]
instead of
auto foo() -> std::tuple<int, int>
auto foo() -> [int& key, int& value]
... well... wouldn't that be nice
auto minmax_element(It begin, It end) -> [It min_it, It max_it];
auto [min = *min_it, max = *max_it] = minmax_element(...);