How to move the future into a lambda expression

I am using Visual Studio 2013 and want to reach this line of code

f = p.get_future(); auto task =[f = std::move(f)](){ //use f }; 

I know the solution here , but unfortunately this does not compile under VS2013 ( error C2558 no copy-constructor available ).

+3
source share
1 answer

You can use shared_future . This is the easiest.

However, this does not help you move. If you really need to move, we can do this with the move_helper function and the class:

 template<class T, class F=void> struct move_helper_t { T t; F f; template<class...Args> auto operator()(Args&&...args) ->typename std::result_of< F&(T&, Args...) >::type { return f(t, std::forward<Args>(args)...); } // force right-associativity of `->*`, and // invert the stack to get the arguments in the "right" order: template<class F1, class R0=move_helper_t< T, typename std::decay<F1>::type > > auto operator->*(F1&& f1) -> decltype( std::declval<F>()->* std::declval<R0>() ) { return std::move(f)->* R0{ std::forward<T>(t), std::forward<F1>(f1) }; } }; template<class T> struct move_helper_t<T,void> { T t; template<class F> auto operator->*(F&& f) -> move_helper_t<T, typename std::decay<F>::type> { return {std::forward<T>(t), std::forward<F>(f)}; } }; template<class T> move_helper_t<std::decay_t<T>> move_helper( T&& t ) { return {std::forward<T>(t)}; } 

In MSVC 2013, you may need to declare a constructor in move_helper_t . I don’t remember how well their return {} code is written.

 f = p.get_future(); task = move_helper(std::move(f)) ->* [](std::future<int>& f){ //use f }; 

->* binds move_helper to lambda. It then returns the called object, which will be passed to std::future<int>& as the first argument when called.

Due to the way it is written, you can even bind it:

 auto f = p.get_future(); auto f2 = p2.get_future(); task = move_helper(std::move(f)) ->* move_helper(std::move(f2)) ->* [](std::future<int>& f, std::future<char>& f2){ //use f }; 

to move more than one argument to lambda.

In both cases, task can be called by task() - the operation ->* binds the lambda up and passes the futures on call.

Living example .

Please note that this solves the problem of translating the future into lambda. If you want to store the lambda in std::function , this will not help you, since functions must be copied.

 template<class F> struct shared_function { std::shared_ptr<F> pf; template<class ...Args> typename std::result_of<F&(Args...)>::type operator()(Args&&...args) const { return (*pf)(std::forward<Args>(args)...); } }; template<class F, class dF=typename std::decay<F>::type > shared_function< dF > make_shared_function( F&& f ) { return {std::make_shared<dF>(std::forward<F>(f))}; } 

this takes a movable lambda and wraps it in a generic pointer and provides operator() for you. But first, using future move it to the lambda using the above technique, and then wrap this lambda in a common function to pass it to std::function , it’s funny: just use shared_future first.

On the side, in theory, a packaged_task only requires moving, but I'm not sure that MSVC2013 supports this requirement.

+3
source

All Articles