Reputation: 1217
I have to wrap a getter function into a std::future
object.
std::function<String (String)>
-> std::function<std::future<String> (String)>
So simple question, what is the best / fastest way to do this?
Here are two options I came up with.
I have a function:
std::function<String (String)> getter;
Then wrap this using std::promise
:
std::function<std::future<String> (String)> binding = [getter](String context) {
std::promise<String> p;
p.set_value(getter(contex));
return p.get_future();
};
Or using std::async
:
std::function<std::future<String> (String)> binding = [getter](String context) {
return std::async(std::launch::deferred, getter, contex);
};
Upvotes: 2
Views: 1112
Reputation: 275385
The right answer is to write your own make_ready_future
(right out of std::experimantal
). std::promise
is about the only way I know of to produce a ready future: async
produces non-ready futures.
This takes a value, and produces a future of that value, with some fancy stuff involving reference wrappers (which you can optionally skip).
A proposal to add it in C++1z exists, so by basing your own version off its interface, you can semi future-proof your code. Plus, as an audited design, it will suck less than your own.
Once you have it written:
template<class F>
auto futuristic_wrapper( F&& f ) {
return [f=std::forward<F>(f)](auto&&...args){
return make_ready_future( f( decltype(args)(args)... ) );
};
}
in C++11 you'd have to write a class to replace the lambda:
template<class F>
struct futurize {
F f;
template<class...Args>
operator()(Args&&...args)const->
delctype(make_ready_future(f(std::forward<Args>(args)...)))
{ return make_ready_future(f(std::forward<Args>(args)...)); }
};
template<class F>
auto futuristic_wrapper( F&& f )->
futurize< typename std::decay_t<F>::type >
{
return {std::forward<F>(f)};
}
which is annoying, but mostly a mechanical transformation.
This doesn't actually produce a std::function< future<R>(Args...) >
, but it will return something convertible to that. No need to type erase if we don't need to after all.
You can put "your own version of to-be-standardized stuff" you steal from std::experimantal
in a namespace like notstd
. Always use it with notstd::
(never using namespace notstd;
, and not using notstd::make_ready_future;
as that risk behavior changes when the type is added to std
) to be clear to later users that this is NOT the standard version of these objects.
Upvotes: 4