ice_planet_hoth_boss
ice_planet_hoth_boss

Reputation: 31

c++: packaged_task via promises

I am attempting implement packaged_task as a template class, using promises.

My compile error says that I am referencing a deleted function. I suspect I need to implement copy and/or move semantics, but I am confused how and where to begin. Any advice is much appreciated:

#include "stdafx.h"
#include <iostream>
#include <future>
#include <functional>
#include <thread>
using namespace std;

//Base case
template<class>
class promised_task;

//Templated class
template<class Ret, class...Args>
class promised_task<Ret(Args...)> {
public:
    //Constructor
    //Takes a function argument that is forwarded to fn member
    template<class F>
    explicit promised_task(F&& f) :fn(f){}

    //get_future member function:
    future<Ret> get_future(){
        return prom.get_future();
    }

    //Set value
    void operator()(Args&&...args){
        prom.set_value(fn(forward<Args>(args)...));
    }

private:
    //Promise member
    promise<Ret> prom;

    //Function member
    function<Ret(Args...)> fn;
};


//Sample function from cplusplus.com
int countdown(int from, int to){
    for (int i = from; i != to; --i){
        cout << i << endl;
        this_thread::sleep_for(chrono::seconds(1));
    }
    cout << "Lift off!" << endl;
    return from - to;
}

//Verification function also from cplusplus.com
int main(){
    promised_task<int(int, int)>tsk(countdown);
    future<int>ret = tsk.get_future();

    thread th(move(tsk), 10, 0);

    int value = ret.get();

    cout << "The countdown lasted for " << value << " seconds." << endl;

    th.join();

    cout << "Press any key to continue:" << endl;
    cin.ignore();
    return 0;
}

Upvotes: 0

Views: 362

Answers (1)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275500

thread th(move(tsk), 10, 0)

I'd guess this is the line generating the error.

Add:

promised_task(promised_task&& o):
  prom(std::move(o).prom), fn(std::move(o).fn)
{}

to promised_task in order to manually write a move ctor. C++11 mandates that the compiler write the above move constructor (or one equivalent) for you. MSVC2013 is not a compliant C++11 compiler.

The error is complaining that it cannot move a promised_task via promised_task(promised_task const&), which is implicitly deleted as promise has no copy constructor. The compiler should write promised_task(promised_task&&), but it isn't a C++11 compiler (not really), so it doesn't, and you get an error about a missing copy constructor.

When you try to move a type, if it lacks a move operation, copy is implicitly called. If copy is deleted/impossible/inaccessible, you get an error about not being able to copy the type.

Note that MSVC2015 is fixing that flaw. The big remaining hole in the MSVC2015 implementation of C++11 is what Microsoft calls "expression SFINAE", and knock-on effects (library components that fail compliance because it needs it to implement it).

In a recent communication about C++11 compliance, they have said they plan to ship that in an update for end-consumers (not a beta) sometime in the MSVC2015 cycle, but not enable the blocked library features until the next major release (to avoid ODR violations).

Upvotes: 1

Related Questions