Suppose I have two functions that return futures:
std::future<T> foo(int);
std::future<U> bar(T const &);
I want to combine the two functions to a function that takes an int as parameter and returns a std::future<U>. How should I write this function? Is it possible to generalize function composition for functions that return futures? 
std::future<U> foobar1(int x)
{
  auto foo_x = foo(x);
  return bar(foo_x.get());
}
This function will block until the future returned by foo is finished, right? This is clearly not what I want.
std::future<U> foobar2(int x)
{
  return std::async([=]()
  {
    auto foo_x = foo(x);
    return bar(foo_x.get()).get();
  });
}
It feels silly to call get() on the future returned by bar just to have it turned into a new future by std::async
std::future<U> foobar3(int x)
{
  return foo(x).then([](std::future<T> f)
  {
    return bar(f.get()).get();
  };
}
Here, again I have to call get() on the future returned by bar otherwise I'd have a future<future<U>>. Is this the correct approach?
What you want is a monad. std::future is almost but not quite a monad but lacks the ability to properly compose functions by lifting them as you have noticed. For a detailed discussion on this please see this blog post.
The summary is that for C++17 an additional method has been proposed for std::future: either next or then which would take a function to be applied to the future's value once it is available. This would be roughly equivalent to bind in Haskell for example (note: not std::bind).
Let's take the two functions:
T foo(int);
U bar(T const &);
Here we have a mapping int -> T -> U, what you want is to lift this mapping to int -> std::future<T> -> std::future<U>. What this might look like would be:
int x = 2;
std::async([=](){return foo(x);}).then(bar);
Where then is a function that automatically maps T -> U to std::future<T> -> std::future<U>.
Disclaimer: I am not a Haskell programmer and realise I have probably got everything mixed up. I gladly welcome corrections.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With