WaeCo
WaeCo

Reputation: 1217

std::async vs std::promise

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

Answers (1)

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

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

Related Questions