如何把std::future<T>转换成std::future<void>?
How to convert std::future<T> to std::future<void>?
我有这样一种情况,我有一个 std::future<some_type>
来自对 API A 的调用,但需要为 API B 提供一个 std::future<void>
:
std::future<some_type> api_a();
void api_b(std::future<void>& depend_on_this_event);
在没有 .then()
或 when_all()
等建议功能的情况下,是否有任何有效的方法可以丢弃附加到 std::future<T>
的值并仅保留底层std::future<void>
代表活动结束?
像下面这样的东西可以工作,但可能效率低下:
auto f = api_a();
f.wait();
auto void_f = std::async(std::launch::defer, []{});
api_b(void_f);
你能得到的最好的可能是:
auto f = api_a();
auto void_f = std::async(std::launch::deferred,[fut = std::move(f)]{ fut.wait();});
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));
}
这是@sbabbi 回答的通用版本。
api_b( convert_future<void>( api_a() ) );
允许任何目标和目标类型透明地工作。
这种方法的最大缺点是所产生的未来是一个延迟的未来包装(可能是异步的)未来,这意味着 .wait_for()
和 .ready()
API 不像异步期货那样工作.返回的未来永远不会准备好,直到等待。
所以我们可以稍微改进一下:
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(); }
);
}
};
至少如果在我们转换它时 future 已经准备好,返回的 future 也准备好了。
我有这样一种情况,我有一个 std::future<some_type>
来自对 API A 的调用,但需要为 API B 提供一个 std::future<void>
:
std::future<some_type> api_a();
void api_b(std::future<void>& depend_on_this_event);
在没有 .then()
或 when_all()
等建议功能的情况下,是否有任何有效的方法可以丢弃附加到 std::future<T>
的值并仅保留底层std::future<void>
代表活动结束?
像下面这样的东西可以工作,但可能效率低下:
auto f = api_a();
f.wait();
auto void_f = std::async(std::launch::defer, []{});
api_b(void_f);
你能得到的最好的可能是:
auto f = api_a();
auto void_f = std::async(std::launch::deferred,[fut = std::move(f)]{ fut.wait();});
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));
}
这是@sbabbi 回答的通用版本。
api_b( convert_future<void>( api_a() ) );
允许任何目标和目标类型透明地工作。
这种方法的最大缺点是所产生的未来是一个延迟的未来包装(可能是异步的)未来,这意味着 .wait_for()
和 .ready()
API 不像异步期货那样工作.返回的未来永远不会准备好,直到等待。
所以我们可以稍微改进一下:
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(); }
);
}
};
至少如果在我们转换它时 future 已经准备好,返回的 future 也准备好了。