implementing future::then() equivalent for asynchronous execution in c++11

I have a few questions about the implementation of the function then() in Herb Sutter's talk. This function is used to chain asynchronous operations, the parameter f is a future from one operation and the parameter w is the 'work' for this operation (lambda).

template <typename Fut, typename Work>
auto then(Fut f, Work w) -> future<decltype(w(f.get()))>
{
    return async([=]{ w(f.get()); });
}

An example of application would be:

    std::future<int> f = std::async([]{
        std::this_thread::sleep_for(std::chrono::microseconds(200));
        return 10;
    });

    auto f2 = then(std::move(f), [](int i){
        return 2 * i;
    });

The main thread spawns the tasks but does not wait for any of them to finish.

Firstly, future<T> does not have a copy constructor. This means, that the suggested implementation can be only used with shared_future<T> unless we change the call to async() to move the future into the lambda. This SO question suggested a way of doing it but it seems too complicated. I re-implemented the function and I am wondering whether my code is correct or whether I missed something...

Secondly, the future that is passed to the then() function might be void so we actually need 2 implementations of then(), right? One for futures returning T and one for futures returning void.

Lastly, should the lambda inside the body of then() not have a return statement so that we can actually return the value back? Without the return statement, then returns future<void>, right?

I tried to address the above points and this is what I came up with. Is it correct?

template <typename T, typename Work>
auto then(future<T> f, Work w) -> future<decltype(w(f.get()))>
{
    return async([](future<T> f, Work w)
                      { return w(f.get()); }, move(f), move(w));
}

template <typename Work>
auto then(future<void> f, Work w) -> future<decltype(w())>
{
    return async([](future<void> f, Work w)
                      { f.wait(); return w(); }, move(f), move(w));
}

Answers


In order to simplify the interface, I would "hide" the void problem inside the implementation, similarly to what Herb did with his concurrent<T> implementation. Instead of having 2 then implementations, declare a helper function get_work_done with 2 implementations:

template <typename T, typename Work>
auto get_work_done(future<T> &f, Work &w)-> decltype(w(f.get()))
{return w(f.get());}

template <typename Work>
auto get_work_done(future<void> &f, Work &w)-> decltype(w())
{f.wait(); return w();}

And then let template parameter detection take care of the rest:

template <typename T, typename Work>
auto then(future<T> f, Work w) -> future<decltype(w(f.get()))>
{
    return async([](future<T> f, Work w)
                      { return get_work_done(f,w); }, move(f), move(w));
}

no, it is not correct. if you pass return value of .get() to continuation, it will not be able to handle exception, propagated from .get(). you have to pass future to continuation, and call .get() manually, just like in boost.thread


Need Your Help

Tomcat: Programmatically remove websocket endpoint

java tomcat

I'm able to programmatically add a websocket server endpoint:

Last column in a table not clickable

javascript jquery html css

I currently have a pretty crazy code that make it possible to click and expand rows in a dynamic table. My problem is that I need to make the last column in the table not clickable, and I have no i...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.