Capturing std :: prom in lambda c ++ 14

I want to create a state machine that processes the transmitted signals in its stream. I use Visual Studio 2015, so C ++ 11 and partially C ++ 14 are supported. Signals are stored in containers. Each signal is represented as a function of std ::. I would like to wait from the client until the state machine processes the signal that was sent, so this is a kind of synchronous signal.

My problem: I cannot commit std :: prom to lambda and add it to the container.

#include <functional> #include <future> #include <list> std::list<std::function<int()>> callbacks; void addToCallbacks(std::function<int()>&& callback) { callbacks.push_back(std::move(callback)); } int main() { std::promise<int> prom; auto fut = prom.get_future(); // I have made the lambda mutable, so that the promise is not const, so that I can call the set_value auto callback = [proms{ std::move(prom) }]() mutable { proms.set_value(5); return 5; }; // This does not compile addToCallbacks(std::move(callback)); // This does not compile either, however this lambda is a temporal value (lvalue) addToCallbacks([proms{ std::move(prom) }]() mutable { proms.set_value(5); return 5; }); return 0; } 

What are the solutions if

  • I want to avoid capturing a promise with a link
  • I want to avoid capturing a * or shared_ptr pointer to promise

It would be nice to put a promise in the class anyway, like a lambda is generated. This means that the lambda is no longer copied, but only movable. Is it possible at all?

+10
c ++ promise lambda c ++ 11 c ++ 14
source share
3 answers

std::function can only be created from functors that can be copied. From [func.wrap.func.con]:

 template<class F> function(F f); template <class F, class A> function(allocator_arg_t, const A& a, F f); 

Requires: F must be CopyConstructible .

std::promise not copied, so there is no way to bind a functor with this member to std::function . Period.

Given that you want your functor to actually take responsibility for the promise, this does not leave you many options. To a large extent, std::shared_ptr<std::promise> . Any other option either does not work (for example, std::unique_ptr<std::promise> ), leaves you with a dangling object (for example, std::reference_wrapper<std::promise> ), or leaves problems with memory management (for example, std::promise* ).


However, you could use something other than std::function . Here you can take a look at the idea here , as well as dyp function_mo here , both of which create movable scents of std::function .

+12
source share

It is trivial to collapse your own class of polymorphic functions. This example corrects the arguments and return types, but if necessary, a little more work can plan them.

 #include <iostream> #include <functional> #include <future> #include <list> // declare a non-polymorphic container for any function object that takes zero args and returns an int // in addition, the contained function need not be copyable class move_only_function { // define the concept of being callable while mutable struct concept { concept() = default; concept(concept&&) = default; concept& operator=(concept&&) = default; concept(const concept&) = delete; concept& operator=(const concept&) = default; virtual ~concept() = default; virtual int call() = 0; }; // model the concept for any given function object template<class F> struct model : concept { model(F&& f) : _f(std::move(f)) {} int call() override { return _f(); } F _f; }; public: // provide a public interface int operator()() // note: not const { return _ptr->call(); } // provide a constructor taking any appropriate object template<class FI> move_only_function(FI&& f) : _ptr(std::make_unique<model<FI>>(std::move(f))) {} private: std::unique_ptr<concept> _ptr; }; std::list<move_only_function> callbacks; void addToCallbacks(move_only_function&& callback) { callbacks.push_back(std::move(callback)); } int main() { std::promise<int> prom; auto fut = prom.get_future(); // I have made the lambda mutable, so that the promise is not const, so that I can call the set_value auto callback = [proms=std::move(prom)]() mutable { proms.set_value(5); return 5; }; // This now compiles addToCallbacks(std::move(callback)); std::promise<int> prom2; auto fut2 = prom2.get_future(); // this also compiles addToCallbacks([proms = std::move(prom2)]() mutable { proms.set_value(6); return 6; }); for (auto& f : callbacks) { std::cout << "call returns " << f() << std::endl; } std::cout << "fut = " << fut.get() << std::endl; std::cout << "fut2 = " << fut2.get() << std::endl; return 0; } 

expected output:

 call returns 5 call returns 6 fut = 5 fut2 = 6 
+3
source share

Another simple approach may be to use the idiom of destructive copying and transfer of the "only movable" type to the trivial CopyConstructible structure:

 #include <functional> #include <future> #include <type_traits> template <typename T> struct destructive_copy_constructible { mutable T value; destructive_copy_constructible() {} destructive_copy_constructible(T&& v): value(std::move(v)) {} destructive_copy_constructible(const destructive_copy_constructible<T>& rhs) : value(std::move(rhs.value)) {} destructive_copy_constructible(destructive_copy_constructible<T>&& rhs) = default; destructive_copy_constructible& operator=(const destructive_copy_constructible<T>& rhs) = delete; destructive_copy_constructible& operator=(destructive_copy_constructible<T>&& rhs) = delete; }; template <typename T> using dcc_t = destructive_copy_constructible<typename std::remove_reference<T>::type>; template <typename T> inline dcc_t<T> move_to_dcc(T&& r) { return dcc_t<T>(std::move(r)); } int main() { std::promise<int> result; std::function<void()> f = [r = move_to_dcc(result)]() { r.value.set_value(42); }; return 0; } 

Although the destructive copy idiom is considered dangerous and deprecated due to the move idiom, it can still be useful, at least in order to close such a std::function hole.

The advantage in this case is the absence of overhead (without copying / dynamic memory allocation) compared with the proposed solutions std::shared_ptr and move_only_function . And the danger of misuse of the copied source object is mainly reduced by using a motion-like syntax that clearly describes the destructive semantics of copy / move.

Another useful side effect is that you do not need to declare the entire lambda variable to set the value to std::promise , because it is already declared in the DCC shell.

+1
source share

All Articles