In order to clarify the core concept, let's reduce it to a more basic example. Although std::tie
is useful for functions returning (a tuple of) more values, we can understand it just fine with just one value:
int a;
std::tie(a) = std::make_tuple(24);
return a; // 24
Things we need to know in order to go forward:
The next step is to get rid of those functions that only get in your way, so we can transform our code to this:
int a;
std::tuple<int&>{a} = std::tuple<int>{24};
return a; // 24
The next step is to see exactly what happens inside those structures.
For this, I create 2 types T
substituent for std::tuple<int>
and Tr
substituent std::tuple<int&>
, stripped down to the bare minimum for our operations:
struct T { // substituent for std::tuple<int>
int x;
};
struct Tr { // substituent for std::tuple<int&>
int& xr;
auto operator=(const T& other)
{
// std::get<I>(*this) = std::get<I>(other);
xr = other.x;
}
};
auto foo()
{
int a;
Tr{a} = T{24};
return a; // 24
}
And finally, I like to get rid of the structures all together (well, it's not 100% equivalent, but it's close enough for us, and explicit enough to allow it):
auto foo()
{
int a;
{ // block substituent for temporary variables
// Tr{a}
int& tr_xr = a;
// T{24}
int t_x = 24;
// = (asignement)
tr_xr = t_x;
}
return a; // 24
}
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
.