Working with futures and .then, I keep running into the problem of needing to capture by move in a lambda. In fact, not only that, but when implementing e.g. when_all, I find myself needing to capture a whole parameter-pack. Neither of these things are supported out of the box in C++17.However, we can capture a whole parameter pack by forward, using std::forward_as_tuple and std::apply. So I decided to write a std::move_as_tuple that would do the same thing as forward_as_tuple but for moving instead of forwarding.How does this code look? And is there a simpler way to accomplish my goal?template<class... Types>constexpr auto move_as_tuple(Types&&... args){    return std::forward_as_tuple(std::move(args)...);}Sample usage (which is also fair game for critique):future<std::tuple<>> when_all(){    promise<std::tuple<>> p;    p.set_value({});    return p.get_future();}template<class F, class... Rest>future<std::tuple<F, Rest...>> when_all(F f, Rest... rest){    return f.then([rest = move_as_tuple(rest...)](auto f) {        auto w = [](auto&&... as) { return when_all(std::forward<decltype(as)>(as)...); };        return std::apply(w, rest).then([f = std::move(f)](auto future_of_tuple_of_rest) {            return std::tuple_cat(std::make_tuple(std::move(f)), future_of_tuple_of_rest.get());        }).get();    });}
`std::move_as_tuple` and `std::when_all`
c++;promise;template meta programming;c++17
(Self-answering for posterity.)There's a major flaw in my above implementation of when_all: It calls .get()! This can cause the thread to block indefinitely. We need to eliminate that .get somehow, or at least make sure that we only ever call .get on a future that has just been passed in as the argument of a .then callback.The reason I was calling .get was to work around a type incompatibility: the type ofauto SUBEXPRESSION =    std::apply(w, rest).then([f = std::move(f)](auto future_of_tuple_of_rest) {        return std::tuple_cat(std::make_tuple(std::move(f)), future_of_tuple_of_rest.get());    })is std::future<std::tuple<F, Rest...>>, which means that the type ofauto EXPRESSION =    f.then([...](auto f) {        return SUBEXPRESSION;    });});is std::future<decltype(SUBEXPRESSION)>, which is to say std::future<std::future<std::tuple<F, Rest...>>>. That's too many futures! So I was trying to work around this by calling .get right before returning the inner future.Turns out that boost::future and std::experimental::future (in the Concurrency TS) already have a solution for this problem. It's called .unwrap, and the idea is that if decltype(f) is future<future<T>>, then decltype(f.unwrap()) is future<T>.In Boost's case, this is currently provided as a constructor explicit future(future<future>&&) instead of as an .unwrap member function, but there's a bug open to provide .unwrap directly.In the Concurrency TS, .then also implicitly calls .unwrap on the callback's return value if that return value is seen to be of type future<future<T>>.So my solution was simply to add a call to .unwrap (well, the Boost explicit constructor), and then everything was happy.There's another showstopping problem with the above code: it doesn't compile for more than one argument, because I'm missing the mutable keyword on both of the lambdas involved. You can't move out of the captured f unless f is non-const, which means you need mutable on the inner lambda; and at least GCC is unhappy with std::apply(w, rest) unless rest is non-const, which means you need mutable on the outer lambda too.Finally, I decided to stop trying to capture references to things, and just replaced everything with capture-by-value. This simplified the code to the point where I didn't see any reason to keep move_as_tuple as its own function at all.My final code:auto when_all() {    promise<tuple<>> p;    p.set_value({});    return p.get_future();}template<class F, class... Rest>auto when_all(F f, Rest... rest) {    return future<tuple<F, Rest...>>(        f.then([rest = make_tuple(std::move(rest)...)](auto f) mutable {            auto w = [](auto... as) { return when_all(std::move(as)...); };            return apply(w, std::move(rest)).then(                [f = std::move(f)](auto future_of_tuple_of_rest) mutable {                    return tuple_cat(make_tuple(std::move(f)), future_of_tuple_of_rest.get());                }            );        })    );}