I'm using Visual Studio 2013 and i want achieve this line of code
f = p.get_future();
auto task =[f = std::move(f)](){
//use f
};
I'm aware of the solution
here, but unfortunately this doesn't compile under VS2013 (error C2558 no copy-constructor available
).
You can use a shared_future
. That is easiest.
However, that doesn't help you move. If you really need to move, we can do it with the help of a move_helper
function and 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 have to declare a constructor in move_helper_t
. I do not recall how well written their return {}
code was.
f = p.get_future();
task =
move_helper(std::move(f)) ->*
[](std::future<int>& f){
//use f
};
->*
binds the move_helper
to the lambda. It then returns a callable object which will be passed the std::future<int>&
as the first argument when invoked.
Because of how it is written, you can even chain 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 into the lambda.
In both cases, task
can be invoked by task()
-- the ->*
operation binds the lambda up and passes the futures when invoked.
Live example.
Note that this solves the problem of moving the future into the lambda. If you want to store the lambda in a std::function
, this will not help you, as functions must be copyable.
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 shared pointer and exposes operator()
for you. But first taking a future
moving it into a lambda via the above technique, and then wrapping that lambda in a shared function to pass it to a std::function
is ridiculous: just use a shared_future
in the first place.
As an aside, in theory, a packaged_task
only requires move, but I am uncertain if MSVC2013 supports that requirement.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With