Is there any semantic difference between writing the expression
std::tie( x, y, z )   and the following expression?
std::make_tuple( std::ref(x), std::ref(y), std::ref(z) )   If so, what are the differences?
By the way, this question is not asking the same as What is the difference between assigning to std::tie and tuple of references? because the tuple of references is not created via std::ref, but by explicitly specifying the type. 
std::make_tupleCreates a tuple object, deducing the target type from the types of arguments. For each Ti in Types... , the corresponding type Vi in VTypes... is std::decay<Ti>::type unless application of std::decay results in std::reference_wrapper<X> for some type X , in which case the deduced type is X& .
std::tie. Constructs a tuple object whose elements are references to the arguments in args , in the same order. This allows a set of objects to act as a tuple, which is especially useful to unpack tuple objects.
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 .
Class template std::tuple is a fixed-size collection of heterogeneous values. It is a generalization of std::pair. If std::is_trivially_destructible<Ti>::value is true for every Ti in Types , the destructor of tuple is trivial.
There is almost† no functional difference between the two expressions. tie() is just shorter whereas make_tuple() is more generic. 
According to [tuple.creation], make_tuple does:
template<class... Types> constexpr tuple<VTypes...> make_tuple(Types&&... t);Let
Uibedecay_t<Ti>for eachTiin Types. Then eachViinVTypesisX&ifUiequalsreference_wrapper<X>, otherwiseViisUi.
Hence std::make_tuple( std::ref(x), std::ref(y), std::ref(z) ) yields† a std::tuple<X&, Y&, Z&>. 
On the other hand, tie does:
template<class... Types> constexpr tuple<Types&...> tie(Types&... t) noexcept;Returns:
tuple<Types&...>(t...). When an argument intisignore, assigning any value to the corresponding tuple element has no effect.
Hence, std::tie(x, y, z) also yields a std::tuple<X&, Y&, Z&>.
†Except in one edge case.
There is a difference when any of x, y and z is a specialization of std::reference_wrapper.
#include <tuple> #include <functional>  void f(std::reference_wrapper<int> x, int y, int z) {     std::tie(x,y,z); // type is std::tuple<std::reference_wrapper<int>&, int&, int&>     std::make_tuple(std::ref(x),std::ref(y),std::ref(z)); // type is std::tuple<int&, int&, int&> } 
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With