Title
packaged_task should have deleted copy c'tor with const parameter
Status
c++14
Section
[futures.task]
Submitter
Daniel Krügler

Created on 2011-06-16.00:00:00 last changed 131 months ago

Messages

Date: 2011-08-16.23:35:18

Proposed resolution:

This wording is relative to the FDIS.

  1. Modify the class template basic_ostream synopsis in [ostream] as indicated (Note: The prototype signature of the move assignment operator in [ostream.assign] is fine):

    namespace std {
      template <class charT, class traits = char_traits<charT> >
      class basic_ostream : virtual public basic_ios<charT,traits> {
        […]
    
        // 27.7.3.3 Assign/swap
        basic_ostream& operator=(const basic_ostream& rhs) = delete;
        basic_ostream& operator=(const basic_ostream&& rhs);
        void swap(basic_ostream& rhs);
    };
    
  2. Modify the class template packaged_task synopsis in [futures.task] p2 as indicated:

    namespace std {
      template<class> class packaged_task; // undefined
    
      template<class R, class... ArgTypes>
      class packaged_task<R(ArgTypes...)> {
      public:
        […]
      
        // no copy
        packaged_task(const packaged_task&) = delete;
        packaged_task& operator=(const packaged_task&) = delete;
        
        […]
      };
      […]
    }
    
Date: 2011-08-16.23:35:18

[ 2011 Bloomington. ]

Move to Ready.

Date: 2011-06-18.20:05:35

Class template packaged_task is a move-only type with the following form of the deleted copy operations:

packaged_task(packaged_task&) = delete;
packaged_task& operator=(packaged_task&) = delete;

Note that the argument types are non-const. This does not look like a typo to me, this form seems to exist from the very first proposing paper on N2276. Using either of form of the copy-constructor did not make much difference before the introduction of defaulted special member functions, but it makes now an observable difference. This was brought to my attention by a question on a German C++ newsgroup where the question was raised why the following code does not compile on a recent gcc:

#include <utility>
#include <future>
#include <iostream>
#include <thread>

int main(){
  std::packaged_task<void()> someTask([]{ std::cout << std::this_thread::get_id() << std::endl; });
  std::thread someThread(std::move(someTask)); // Error here
  // Remainder omitted
}

It turned out that the error was produced by the instantiation of some return type of std::bind which used a defaulted copy-constructor, which leads to a const declaration conflict with [class.copy] p8.

Some aspects of this problem are possibly core-language related, but I consider it more than a service to programmers, if the library would declare the usual form of the copy operations (i.e. those with const first parameter type) as deleted for packaged_task to prevent such problems.

A similar problem exists for class template basic_ostream in [ostream]:

namespace std {
  template <class charT, class traits = char_traits<charT> >
  class basic_ostream : virtual public basic_ios<charT,traits> {
    […]

    // 27.7.3.3 Assign/swap
    basic_ostream& operator=(basic_ostream& rhs) = delete;
    basic_ostream& operator=(const basic_ostream&& rhs);
    void swap(basic_ostream& rhs);
};

albeit this could be considered as an editorial swap of copy and move assignment operator, I suggest to fix this as part of this issue as well.

History
Date User Action Args
2014-02-20 13:20:35adminsetstatus: wp -> c++14
2012-02-12 18:36:43adminsetstatus: voting -> wp
2012-02-09 04:07:48adminsetstatus: ready -> voting
2011-08-16 23:35:18adminsetmessages: + msg5857
2011-08-16 23:35:18adminsetstatus: new -> ready
2011-06-16 21:35:33adminsetmessages: + msg5820
2011-06-16 00:00:00admincreate