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

Section: 20.5.3.1 [utility.arg.requirements] Status: Open Submitter: Nikolay Ivchenkov Opened: 2012-03-23 Last modified: 2016-06-28

Priority: 2

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

View all issues with Open status.

Discussion:

According to 20.5.3.1 [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.

Proposed resolution: