Title
Are reference types CopyConstructible/MoveConstructible/CopyAssignable/MoveAssignable/Destructible?
Status
open
Section
[utility.arg.requirements]
Submitter
Nikolay Ivchenkov

Created on 2012-03-23.00:00:00 last changed 2 weeks ago

Messages

Date: 2024-12-15.00:00:00

[ 2024-12-04; Daniel comments ]

The mentioned requirement sets have been renamed a while ago to:

  • Cpp17CopyConstructible

  • Cpp17MoveConstructible

  • Cpp17CopyAssignable

  • Cpp17MoveAssignable

  • Cpp17Destructible

Date: 2024-03-15.00:00:00

[ 2024-03-15; LWG 4047 addresses the swap part ]

Date: 2020-10-15.00:00:00

[ 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 [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.

Date: 2019-07-22.17:12:46

[ 2019 Cologne Wednesday night ]

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

Date: 2018-06-12.02:06:47

[ 2018-06, Rapperwsil ]

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

Date: 2016-06-21.05:55:22

[ 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.

Date: 2016-03-08.22:51:25

[ 2016-03, Jacksonville ]

Casey volunteers to make a survey

Date: 2015-11-04.16:49:21

[ 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?

Date: 2013-03-15.00:00:00

[ 2013-03-15 Issues Teleconference ]

Moved to Open.

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

Date: 2012-03-23.00:00:00

According to [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?

History
Date User Action Args
2024-12-04 19:46:46adminsetmessages: + msg14510
2024-03-15 14:32:54adminsetmessages: + msg14018
2020-10-02 18:55:49adminsetmessages: + msg11502
2019-07-22 17:12:46adminsetmessages: + msg10484
2018-06-12 02:06:47adminsetmessages: + msg9896
2016-06-21 05:55:22adminsetmessages: + msg8188
2016-03-08 22:51:25adminsetmessages: + msg8018
2015-11-04 16:49:21adminsetmessages: + msg7596
2013-03-18 14:33:00adminsetmessages: + msg6406
2013-03-18 13:02:36adminsetstatus: new -> open
2012-03-23 00:00:00admincreate