This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of C++20 status.

### 2993. `reference_wrapper<T>` conversion from `T&&`

Section: 22.10.6 [refwrap] Status: C++20 Submitter: Tim Song Opened: 2017-06-28 Last modified: 2021-02-25

Priority: 3

View all other issues in [refwrap].

View all issues with C++20 status.

Discussion:

`reference_wrapper<T>` has a deleted constructor taking `T&&` in order to prevent accidentally wrapping an rvalue (which can otherwise happen with the `reference_wrapper(T&)` constructor if `T` is a non-`volatile` `const`-qualified type). Unfortunately, a deleted constructor can still be used to form implicit conversion sequences, so the deleted `T&&` constructor has the (presumably unintended) effect of creating an implicit conversion sequence from a `T` rvalue to a `reference_wrapper<T>`, even though such a conversion would be ill-formed if actually used. This is visible in overload resolution:

>     void meow(std::reference_wrapper<int>); //#1
>     void meow(convertible_from_int); //#2
>     meow(0); // error, ambiguous; would unambiguously call #2 if #1 instead took int&

and in conditional expressions (and hence `std::common_type`) after core issue 1895:

>     std::reference_wrapper<int> purr();

>     auto x = true? purr() : 0; // error, ambiguous: ICS exists from int prvalue to
>                                // reference_wrapper<int> and from reference_wrapper<int> to int

>     using t = std::common_type_t<std::reference_wrapper<int>, int>; // error: no member 'type' because the conditional
>                                                                     // expression is ill-formed

The latter in turn interferes with the use of `reference_wrapper` as a proxy reference type with proxy iterators.

We should ensure that there is no implicit conversion sequence from `T` rvalues to `reference_wrapper<T>`, not just that the conversion will be ill-formed when used. This can be done by using a suitably constrained constructor template taking a forwarding reference instead of the current pair of constructors taking `T&` and `T&&`.

[2017-06-29, Tim adds P/R and comments]

The draft P/R below uses a conditional `noexcept` specification to ensure that converting a `T&` to a `reference_wrapper<T>` remains `noexcept` and make it not usable when the source type is a `reference_wrapper` of the same type so as to avoid affecting `is_trivially_constructible`. It adds a deduction guide as the new constructor template will not support class template argument deduction.

The constructor template has the additional effect of making `reference_wrapper<T>` convertible from everything that is convertible to `T&`. This implies, for instance, that `reference_wrapper<int>` is now convertible to `reference_wrapper<const int>` when it wasn't before (the conversion would have required two user-defined conversions previously). This more closely emulates the behavior of an actual reference, but does represent a change to the existing behavior.

If perfectly emulating the existing behavior is desired, a conditionally-explicit constructor that is only implicit if `T` is reference-compatible with `remove_reference_t<U>` (see 9.4.4 [dcl.init.ref]) can be used.

[2017-07 Toronto Tuesday PM issue prioritization]

Priority 3; what else in the library does this affect? `ref` or `cref`?

[2016-07, Toronto Saturday afternoon issues processing]

Status to Ready.

Proposed resolution:

This wording is relative to N4659.

1. Edit 22.10.6 [refwrap], class template `reference_wrapper` synopsis, as indicated:

   >     namespace std {
   >       template <class T> class reference_wrapper {
   >         […]
   >         // construct/copy/destroy
   >         reference_wrapper(T&) noexcept;
   >         reference_wrapper(T&&) = delete;    // do not bind to temporary objects
   >         template <class U>
   >           reference_wrapper(U&&) noexcept(see below);
   >         […]
   >       };
   >       template <class T>
   >       reference_wrapper(T&) -> reference_wrapper<T>;
   >       […]
   >     }

2. Edit 22.10.6.2 [refwrap.const]/1 as indicated:

   >     reference_wrapper(T& t) noexcept;

   > > -1- Effects: Constructs a `reference_wrapper` object that stores a reference to `t`.

   >     template<class U>
   >       reference_wrapper(U&& u) noexcept(see below);

   > > -?- Remarks: Let `FUN` denote the exposition-only functions

   > > >     void FUN(T&) noexcept;
   > > >     void FUN(T&&) = delete;

   > > This constructor shall not participate in overload resolution unless the expression `FUN(declval<U>())` is well-formed and `is_same_v<decay_t<U>, reference_wrapper>` is `false`. The expression inside `noexcept` is equivalent to `noexcept(FUN(declval<U>()))`.

   > > -?- Effects: Creates a variable `r` as if by `T& r = std::forward<U>(u)`, then constructs a `reference_wrapper` object that stores a reference to `r`.