How to convert std :: future <T> to std :: future <void>?
I have a situation where I have std::future<some_type> called by calling API A, but you need to provide API B with std::future<void> :
std::future<some_type> api_a(); void api_b(std::future<void>& depend_on_this_event); In the absence of the proposed functionality, such as .then() or when_all() , is there an efficient way to throw away the value attached to std::future<T> and leave only the base std::future<void> representing the completion of the event?
Something like the following might work, but would be potentially ineffective:
auto f = api_a(); f.wait(); auto void_f = std::async(std::launch::defer, []{}); api_b(void_f); template<class U> struct convert_future_t { template<class T> std::future<U> operator()( std::future<T>&& f ) const { return std::async(std::launch::deferred, [f=std::move(f)]()->U{ return f.get(); } ); } } template<> struct convert_future_t<void> { template<class T> std::future<void> operator()( std::future<T>&& f ) const { return std::async(std::launch::deferred, [f=std::move(f)]()->void{ f.get(); } ); } } template<class U, class T> std::future<U> convert_future( std::future<T>&& f ) { return convert_future_t<U>{}(std::move(f)); } This is a common version of @sbabbi's answer.
api_b( convert_future<void>( api_a() ) ); which allows you to transparently work with any type of target and type dest.
The big drawback of this approach is that the resulting future is a deferred future packaging (possibly asynchronous) future, which means that the .wait_for() and .ready() APIs do not work like asynchronous futures. The returned future will never be ready until you wait.
So, we can improve this a bit:
template<class T> struct ready_future_t { template<class...Us> std::future<T> operator()( Us&&...us ) const { std::promise<T> p; p.set_value(T(std::forward<Us>(us)...)); return p.get_future(); } }; template<> struct ready_future_t<void> { using T=void; // throws away the Us&&...s template<class...Us> std::future<T> operator()( Us&&...us ) const { std::promise<T> p; p.set_value(); return p.get_future(); } }; template<class T, class...Us> std::future<T> ready_future(Us&&...us){ return ready_future_t<T>{}(std::forward<Us>(us)...); } template<class U> struct convert_future_t { template<class T> std::future<U> operator()( std::future<T>&& f ) const { if (f.wait_for(0ms)==std::future_status::ready) return ready_future<U>(f.get()); return std::async(std::launch::deferred, [f=std::move(f)]()->U{ return f.get(); } ); } }; template<> struct convert_future_t<void> { template<class T> std::future<void> operator()( std::future<T>&& f ) const { if (f.wait_for(0ms)==std::future_status::ready) return ready_future<void>(); return std::async(std::launch::deferred, [f=std::move(f)]()->void{ f.get(); } ); } }; where, at least, if the future was ready for the moment of its transformation, the future returns.