I'm trying to bypass std::packaged_task's lack of a copy constructor so that I can pass it into a std::function (which will only ever be moved).
I inherited from std::packaged_task and added a dummy copy constructor, which I assume shouldn't be called if I never copy the std::function it's moved into.
#include <iostream>
#include <future>
#include <functional>
#include <thread>
template <typename T>
class MyPackagedTask : public std::packaged_task<T()> {
public:
template <typename F>
explicit MyPackagedTask(F&& f)
: std::packaged_task<T()>(std::forward<F>(f)) {}
MyPackagedTask(MyPackagedTask&& other)
: std::packaged_task<T()>(std::move(other)) {}
MyPackagedTask(const MyPackagedTask& other) {
// Adding this borks the compile
}
};
int main()
{
MyPackagedTask<int> task([]() {return 0;});
auto future = task.get_future();
std::thread t(std::move(task));
t.join();
std::cout << future.get() << std::endl;
}
Compiling this with gcc 6.2.1 I get the following error message (just the end part, let me know if you want the whole thing...):
/usr/include/c++/6.2.1/future:1325:6: error: invalid use of void expression
(*_M_result)->_M_set((*_M_fn)());
The error message was unparseable to me, so I was wondering if I'm doing something wrong or if the compiler is failing.
The move constructor definition is not correct, it forwards std::packaged_task<T()>&&
as MyPackagedTask&&
and that invokes a wrong constructor of std::packaged_task<T()>
. This is the cause of the compiler error you observe.
The correct one:
MyPackagedTask(MyPackagedTask&& other)
: std::packaged_task<T()>(static_cast<std::packaged_task<T()>&&>(other))
{}
In there static_cast<std::packaged_task<T()>&&>(other)
does both the upcast to the base class and std::move
.