Come convertire std :: future in std :: future ?

Ho una situazione in cui ho uno std::future risultante da una chiamata all’API A, ma std::future fornire API B con uno std::future :

 std::future api_a(); void api_b(std::future& depend_on_this_event); 

In assenza di funzionalità proposte come .then() o when_all() , esiste un modo efficace per eliminare il valore associato a uno std::future ed essere lasciato solo con il sottostante std::future rappresenta il completamento dell’evento?

Qualcosa come il seguente potrebbe funzionare ma sarebbe potenzialmente inefficiente:

 auto f = api_a(); f.wait(); auto void_f = std::async(std::launch::defer, []{}); api_b(void_f); 

Il meglio che puoi ottenere è probabilmente questo:

 auto f = api_a(); auto void_f = std::async(std::launch::deferred,[fut = std::move(f)]{ fut.wait();}); api_b(void_f); 
 template struct convert_future_t { template std::future operator()( std::future&& f ) const { return std::async(std::launch::deferred, [f=std::move(f)]()->U{ return f.get(); } ); } } template<> struct convert_future_t { template std::future operator()( std::future&& f ) const { return std::async(std::launch::deferred, [f=std::move(f)]()->void{ f.get(); } ); } } template std::future convert_future( std::future&& f ) { return convert_future_t{}(std::move(f)); } 

questa è una versione generica della risposta di @ sbabbi.

 api_b( convert_future( api_a() ) ); 

che consente a qualsiasi tipo di destinazione e destinazione di funzionare in modo trasparente.

Il grande svantaggio di questo approccio è che il futuro che ne deriva è un futuro differito che avvolge un futuro (possibilmente asincrono), il che significa che le .wait_for() e .ready() non funzionano come fanno i futuri asincroni. Il futuro restituito non sarà mai pronto fino all’esaurimento.

Quindi possiamo migliorare questo marginalmente:

 template struct ready_future_t { template std::future operator()( Us&&...us ) const { std::promise p; p.set_value(T(std::forward(us)...)); return p.get_future(); } }; template<> struct ready_future_t { using T=void; // throws away the Us&&...s template std::future operator()( Us&&...us ) const { std::promise p; p.set_value(); return p.get_future(); } }; template std::future ready_future(Us&&...us){ return ready_future_t{}(std::forward(us)...); } template struct convert_future_t { template std::future operator()( std::future&& f ) const { if (f.wait_for(0ms)==std::future_status::ready) return ready_future(f.get()); return std::async(std::launch::deferred, [f=std::move(f)]()->U{ return f.get(); } ); } }; template<> struct convert_future_t { template std::future operator()( std::future&& f ) const { if (f.wait_for(0ms)==std::future_status::ready) return ready_future(); return std::async(std::launch::deferred, [f=std::move(f)]()->void{ f.get(); } ); } }; 

dove almeno se il futuro era già pronto al momento della conversione, anche il futuro restituito è pronto.

esempio dal vivo