Forward function to lambda expression in C ++ 11

To implement Packaged_Task in C ++ 11, I want to achieve what I expressed in C ++ 14 below. In other words, I want to move on to lambda expression.

template<class F> Packaged_Task(F&& f) { Promise<R> p; _future = p.get_future(); auto f_holder = [f = std::forward<F>(f)]() mutable { return std::move(f); }; ///... 

I know about workarounds for moving to lambda (but, unfortunately, these workarounds need a default construct object, in my case the object is most often a lambda expression without a constructor constructor)

+6
source share
3 answers

How to create a wrapper structure that performs a move when building a copy :( (I know this is bad, makes me remember auto_ptr )

 template <typename F> struct Wrapped { using Ftype = typename std::remove_reference<F>::type; Wrapped(Ftype&& f): f_(std::move(f)) {} Wrapped(const Wrapped& o): f_(std::move(o.f_)) {} mutable Ftype f_; }; template<class F> Packaged_Task(F&& f) { Promise<R> p; _future = p.get_future(); Wrapped<std::remove_reference<decltype(f)>::type> wrap(std::forward<F>(f)); auto f_holder = [wrap]() mutable { return std::move(wrap.f_); }; 

This is just a rough idea. Not compiled or tested.

NOTE. I have seen this technique before, I donโ€™t remember whether it was on SO itself or on some blog.

+3
source

First, let me reduce the question to its essence: the function object is somewhat distracting. Essentially, you want to create a lambda with a grip containing an object just for moving. In C ++ 11, which is not directly supported, which made it possible to raise the C ++ 14 approach, which allows you to specify how the assembly is created.

For C ++ 11, you must use a copy. Since the base type does not support copying, it becomes necessary to actually move the object, rather than copy it. This can be achieved with a suitable wrapper that defines a copy constructor that is not copied, but rather moved. Here is an example showing that:

 #include <utility> struct foo { foo(int) {} foo(foo&&) = default; foo(foo const&) = delete; }; template <typename T> class move_copy { T object; public: move_copy(T&& object): object(std::move(object)) {} move_copy(move_copy& other): object(std::move(other.object)) {} T extract() { return std::forward<T>(this->object); } }; template <typename T> void package(T&& object) { move_copy<T> mc(std::forward<T>(object)); foo g = [mc]() mutable { return mc.extract(); }(); } int main() { foo f(0); package(std::move(f)); } 

The move_copy<T> wrapper actually just captures the argument as it is passed: if the lvalue is passed, the lvalue is captured. To correctly capture the contained object, extract() member std::forward<T>() object: this function can only be called once safely, since the object potentially moves from there.

+3
source

Breaking the semantics of a copy, making it a movement, is a bad idea. If this was the only option, go for it, but it is not.

Instead, we can pass the moved value as an argument to lambda and move it to the packaging code.

curry_apply takes some value and a function object and returns this function object with the value associated with the first argument.

 template<class T, class F> struct curry_apply_t { T t; F f; template<class...Args> auto operator()(Args&&...args) -> typename std::result_of_t<F&(T&, Args...)>::type { return f(t, std::forward<Args>(args)...); } }; template<class T, class F> curry_apply_t<typename std::decay<T>::type, typename std::decay<F>::type> curry_apply( T&& t, F&& f ) { return {std::forward<T>(t), std::forward<F>(f)}; } 

Using:

 template<class F> Packaged_Task(F&& f) { Promise<R> p; _future = p.get_future(); auto f_holder = curry_apply( std::move(_future), [](Future<R>& f) mutable { return std::move(f); }; ); 

basically we store the moved data outside of the lambda in a hand-written function object. Then we pass it as an lvalue argument at the beginning of the lambda argument list.

Here is a more complex version of the same solution.

+1
source

All Articles