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

### 3724. `decay-copy` should be constrained

Section: 16.3.3.2 [expos.only.func] Status: WP Submitter: Hui Xie Opened: 2022-06-23 Last modified: 2022-07-25

Priority: 3

View all other issues in [expos.only.func].

View all issues with WP status.

Discussion:

The spec of `views::all` 26.7.6.1 [range.all.general] p2 says:

> Given a subexpression `E`, the expression `views::all(E)` is expression-equivalent to:

> 1. (2.1) — `decay-copy(E)` if the decayed type of E models `view`.

> 2. […]

If `E` is an lvalue move-only `view`, according to the spec, `views::all(E)` would be expression-equivalent to `decay-copy(E)`.

However, 16.3.3.2 [expos.only.func] p2 defines `decay-copy` as follows

>     template<class T> constexpr decay_t<T> decay-copy(T&& v)
>         noexcept(is_nothrow_convertible_v<T, decay_t<T>>)         // exposition only
>       { return std::forward<T>(v); }

It is unconstrained. As a result, for the above example, `views::all(E)` is a well-formed expression and it would only error on the template instantiation of the function body of `decay-copy`, because `E` is an lvalue of move-only type and not copyable.

I think this behaviour is wrong, instead, we should make `decay-copy(E)` ill-formed if it is not copyable, so that `views::all(E)` can be SFINAE friendly.

[2022-07-08; Reflector poll]

Set priority to 3 after reflector poll.

[2022-07-11; Reflector poll]

Set status to Tentatively Ready after seven votes in favour during reflector poll.

[2022-07-15; LWG telecon: move to Ready]

[2022-07-25 Approved at July 2022 virtual plenary. Status changed: Ready → WP.]

Proposed resolution:

This wording is relative to N4910.

1. Modify 16.3.3.2 [expos.only.func] as indicated:

   > -2- The following are defined for exposition only to aid in the specification of the library:

   > >     namespace std {
   > >       template<class T>
   > >         requires convertible_to<T, decay_t<T>>
   > >           constexpr decay_t<T> decay-copy(T&& v)
   > >             noexcept(is_nothrow_convertible_v<T, decay_t<T>>) // exposition only
   > >           { return std::forward<T>(v); }
   > >       […]
   > >     }