如何将未来转移到 lambda 表达式中
How to move future into lambda-expression
我正在使用 Visual Studio 2013,我想实现这行代码
f = p.get_future();
auto task =[f = std::move(f)](){
//use f
};
我知道解决方法
here,但不幸的是,这不能在 VS2013 下编译 (error C2558 no copy-constructor available
)。
您可以使用 shared_future
。那是最简单的。
然而,这并不能帮助你移动。如果你真的需要移动,我们可以借助 move_helper
函数和 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)};
}
在 MSVC 2013 中,您可能 必须在 move_helper_t
中声明构造函数。我不记得他们的 return {}
代码写得有多好。
f = p.get_future();
task =
move_helper(std::move(f)) ->*
[](std::future<int>& f){
//use f
};
->*
将 move_helper
绑定到 lambda。然后它 returns 一个可调用对象,在调用时将作为第一个参数传递给 std::future<int>&
。
由于它的编写方式,您甚至可以将其链接起来:
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
};
将多个参数移动到 lambda 中。
在这两种情况下,task
都可以由 task()
调用——->*
操作绑定 lambda 并在调用时传递期货。
请注意,这解决了将 future 移入 lambda 的问题。如果您想将 lambda 存储在 std::function
中,这个 对您没有帮助,因为函数必须是可复制的。
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))};
}
这需要一个可移动的 lambda 并将其包装在一个共享指针中并为您公开 operator()
。但是首先通过上述技术将 future
移动到 lambda,然后将该 lambda 包装在共享函数中以将其传递给 std::function
是荒谬的:只需使用 shared_future
第一名。
顺便说一句,理论上,packaged_task
只需要移动,但我不确定MSVC2013是否支持该要求。
我正在使用 Visual Studio 2013,我想实现这行代码
f = p.get_future();
auto task =[f = std::move(f)](){
//use f
};
我知道解决方法
here,但不幸的是,这不能在 VS2013 下编译 (error C2558 no copy-constructor available
)。
您可以使用 shared_future
。那是最简单的。
然而,这并不能帮助你移动。如果你真的需要移动,我们可以借助 move_helper
函数和 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)};
}
在 MSVC 2013 中,您可能 必须在 move_helper_t
中声明构造函数。我不记得他们的 return {}
代码写得有多好。
f = p.get_future();
task =
move_helper(std::move(f)) ->*
[](std::future<int>& f){
//use f
};
->*
将 move_helper
绑定到 lambda。然后它 returns 一个可调用对象,在调用时将作为第一个参数传递给 std::future<int>&
。
由于它的编写方式,您甚至可以将其链接起来:
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
};
将多个参数移动到 lambda 中。
在这两种情况下,task
都可以由 task()
调用——->*
操作绑定 lambda 并在调用时传递期货。
请注意,这解决了将 future 移入 lambda 的问题。如果您想将 lambda 存储在 std::function
中,这个 对您没有帮助,因为函数必须是可复制的。
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))};
}
这需要一个可移动的 lambda 并将其包装在一个共享指针中并为您公开 operator()
。但是首先通过上述技术将 future
移动到 lambda,然后将该 lambda 包装在共享函数中以将其传递给 std::function
是荒谬的:只需使用 shared_future
第一名。
顺便说一句,理论上,packaged_task
只需要移动,但我不确定MSVC2013是否支持该要求。