I want to make a state machine which works processes the submitted signals in its own thread. I use Visual Studio 2015, so C++11 and partially C++14 is supported. Signals are stored in containers. Each signal is represented as an std::function. I would like to wait from the client until the state machine processes the signal that was submitted, so it is a kind of synchronous signal.
My problem is: I cannot capture an std::promise into a 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
It would be nice to embed the promise into the class somehow that the lambda generates. This means that the lambda is not copyable any more, only moveable. Is it possible at all?
std::function
can only be constructed from functors that are copyable. 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
shall be CopyConstructible.
std::promise
is non-copyable, so there's no way to stick a functor with this member into a std::function
. Period.
Given that you want your functor to actually take ownership of the promise, this doesn't leave you many options. Pretty much std::shared_ptr<std::promise>
. Any other option either doesn't work (e.g. std::unique_ptr<std::promise>
), leaves you with a dangling object (e.g. std::reference_wrapper<std::promise>
), or leaves you with memory-management issues (e.g. std::promise*
).
You could, however, use something other than std::function
. You can take a look at Yakk's task
idea here, as well as dyp's function_mo
here, both of which create movable flavors of std::function
.