Capture std::promise in a lambda C++14

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.


It's trivial to roll your own polymorphic function class. This example fixes the argument and return types, but a little more work could templatise them if desired.

#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