Search code examples
c++c++11tuplesreference-wrapper

Why does std::make_tuple turn std::reference_wrapper<X> arguments into X&?


In the C++11 standard it states that (see cppreference.com, see also section 20.4.2.4 of the standard) it states that

template< class... Types >
tuple<VTypes...> make_tuple( Types&&... args );

Creates 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&.

I am wondering: Why are reference wrappers treated special here?


Solution

  • This is more or less the primary purpose of reference_wrapper.

    Normally, std::make_tuple always makes tuples of values (std::decay simulates pass-by-value semantics). Given int x, y; std::make_tuple(x, y); makes a std::tuple<int, int>, even though it will have deduced Types as a pack of references int&, int&. std::decay converts those to int, int.

    reference_wrapper allows you to force creation of tuples of references: std::make_tuple(std::ref(x), y) will make a std::tuple<int&, int>.

    Other parts of the standard library use reference_wrapper in the same way. As an example, std::bind will usually copy/move the bound arguments into the resulting object, but if you want it to store only a reference, you can explicitly request it by passing a reference_wrapper.