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

### 2067. `packaged_task` should have deleted copy c'tor with const parameter

Section: 33.10.10 [futures.task] Status: C++14 Submitter: Daniel Krügler Opened: 2011-06-16 Last modified: 2016-01-28

Priority: Not Prioritized

View all other issues in [futures.task].

View all issues with C++14 status.

Discussion:

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

[ 2011 Bloomington. ]

Move to Ready.

Proposed resolution:

This wording is relative to the FDIS.

1. Modify the class template `basic_ostream` synopsis in 31.7.6.2 [ostream] as indicated (Note: The prototype signature of the move assignment operator in 31.7.6.2.3 [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 33.10.10 [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;

   >         […]
   >       };
   >       […]
   >     }