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

### 2146. Are reference types `Copy`/`Move-Constructible`/`Assignable` or `Destructible`?

Section: 16.4.4.2 [utility.arg.requirements] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-03-23 Last modified: 2020-10-02

Priority: 3

View all other issues in [utility.arg.requirements].

View all issues with Open status.

Discussion:

According to 16.4.4.2 [utility.arg.requirements] p1

> The template definitions in the C++ standard library refer to various named requirements whose details are set out in tables 17-24. In these tables, `T` is an object or reference type to be supplied by a C++ program instantiating a template; `a`, `b`, and `c` are values of type (possibly `const`) `T`; `s` and `t` are modifiable lvalues of type `T`; `u` denotes an identifier; `rv` is an rvalue of type `T`; and `v` is an lvalue of type (possibly `const`) `T` or an rvalue of type `const T`.

Is it really intended that `T` may be a reference type? If so, what should `a`, `b`, `c`, `s`, `t`, `u`, `rv`, and `v` mean? For example, are "`int &`" and "`int &&`" `MoveConstructible`?

As far as I understand, we can explicitly specify template arguments for `std::swap` and `std::for_each`. Can we use reference types there?

1. >     #include <iostream>
   >     #include <utility>

   >     int main()
   >     {
   >       int x = 1;
   >       int y = 2;
   >       std::swap<int &&>(x, y); // undefined?
   >       std::cout << x << " " << y << std::endl;
   >     }

2. >     #include <algorithm>
   >     #include <iostream>
   >     #include <iterator>
   >     #include <utility>

   >     struct F
   >     {
   >       void operator()(int n)
   >       {
   >         std::cout << n << std::endl;
   >         ++count;
   >       }
   >       int count;
   >     } f;

   >     int main()
   >     {
   >       int arr[] = { 1, 2, 3 };
   >       auto&& result = std::for_each<int *, F &&>( // undefined?
   >         std::begin(arr),
   >         std::end(arr),
   >         std::move(f));
   >       std::cout << "count: " << result.count << std::endl;
   >     }

Are these forms of usage well-defined?

Let's also consider the following constructor of `std::thread`:

>     template <class F, class ...Args>
>     explicit thread(F&& f, Args&&... args);

> > Requires: `F` and each `Ti` in `Args` shall satisfy the `MoveConstructible` requirements.

When the first argument of this constructor is an lvalue (e.g. a name of a global function), template argument for `F` is deduced to be lvalue reference type. What should "`MoveConstructible`" mean with regard to an lvalue reference type? Maybe the wording should say that `std::decay<F>::type` and each `std::decay<Ti>::type` (where `Ti` is an arbitrary item in `Args`) shall satisfy the `MoveConstructible` requirements?

[2013-03-15 Issues Teleconference]

Moved to Open.

The questions raised by the issue are real, and should have a clear answer.

[2015-10, Kona Saturday afternoon]

STL: std::thread needs to be fixed, and anything behaving like it needs to be fixed, rather than reference types. std::bind gets this right. We need to survey this. GR: That doesn't sound small to me. STL: Seach for CopyConstructible etc. It may be a long change, but not a hard one.

MC: It seems that we don't have a PR. Does anyone have one? Is anyone interested in doing a survey?

[2016-03, Jacksonville]

Casey volunteers to make a survey

[2016-06, Oulu]

During an independent survey performed by Daniel as part of the analysis of LWG 2716, some overlap was found between these two issues. Daniel suggested to take responsibility for surveying LWG 2146 and opined that the P/R of LWG 2716 should restrict to forwarding references, where the deduction to lvalue references can happen without providing an explicit template argument just by providing an lvalue function argument.

[2018-06, Rapperwsil]

Jonathan says that this will be covered by his Omnibus requirements paper.

[2019 Cologne Wednesday night]

Daniel will start working on this again; Marshall to provide rationale why some of the examples are not well-formed.

[2020-10-02; Issue processing telecon: change from P2 to P3]

For the examples given in the original report, the `for_each` case is now banned, because 25.2 [algorithms.requirements] p15 forbids explicit template argument lists. `std::thread`'s constructor has also been fixed to describe the requirements on `decay_t<T>` instead of `T`.

We believe we're more careful these days about using `remove_cvref` or `decay` as needed, but there are still places where we incorrectly state requirements in terms of types that might be references. The `swap` case still needs solving. Still need a survey.

Proposed resolution: