11

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?

Ralph Tandetzky
  • 22,780
  • 11
  • 73
  • 120
  • I think the main point is `std::reference_wrapper` is a conventional marker (treated specially) that was necessary before rvalue references, see http://stackoverflow.com/questions/20080493/semantics-for-wrapped-objects-reference-value-by-default-via-stdmove-stdref?rq=1 . I think it should be necessary anymore in C++11 but the convention persisted. – alfC Dec 12 '15 at 20:11

3 Answers3

11

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.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • Note that this makes it impossible to `make_tuple` and generate a `tuple` containing a `std::reference_wrapper`, but you can `make_tuple` and generate a `tuple` containing `std::reference_wrapper&`. I find this amusing. – Yakk - Adam Nevraumont Sep 27 '13 at 15:31
  • Yeah, but there's little advantage of a tuple of reference_wrappers over a tuple of references. – R. Martinho Fernandes Sep 27 '13 at 15:33
4

Your title is misleading: using std::reference_wrapper<X> turns the members to be X& rather than X. The reason this transformation is done is that std::reference_wrapper<T> is an auxiliary type, meant to turn a value type into a reference type. However, the extra conversion needed to make it appear that way sometimes interferes with the usage. Thus, unwrapping the reference where possible seems a reasonable approach: making the std::tuple<...> member a T& makes the use more natural.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
0

People are usually using std::reference_wrapper<X> to hold non-copyable types. Therefore, copying them in make_tuple would beat the purpose (and may break the build if the copy constructor is deleted). That is the reason why it uses reference (instead of a value) in it's return type.

BЈовић
  • 62,405
  • 41
  • 173
  • 273