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); 
+4
source share
2 answers

The best you can get is probably:

 auto f = api_a(); auto void_f = std::async(std::launch::deferred,[fut = std::move(f)]{ fut.wait();}); api_b(void_f); 
+8
source
 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.

living example

+1
source

All Articles