Is there a name for this handy wrapper around std :: future :: then?

In the jQuery version of Deferred (which C ++ calls "futures"), the method .then()takes as an argument a function whose signature does not contain futures. Whereas .then(), proposed for C ++ 17 ( see N3721 ), performs the function c futurein its signature.

Ie if I want to calculate f(g(x))"in the background", N3721 wants me to write

extern int f(int);
extern int g(int);

auto async_fg(int x) {
    return std::async(f, x).then([](std::future<int> mid) {
        return g(mid.get());
    });
}

I am tempted to write a shell, for example:

template<class F>
auto futurize(F&& f) {
    return [](auto mid) {
        return std::forward<F>(f)(mid.get());
    };
}

auto async_fg(int x) {
    return std::async(f, x).then(futurize(g));
}

Both solutions seem uncomfortable; and besides, I don’t know the correct name for the operation, which I call "futurize" here. If this operation has been proposed before, what do people call it?


, , future<T> -

template<class T, class F>
auto future<T>::then_futurize(F&& f)
{
    return this->then(futurize(std::forward<F>(f)));
}

auto async_fg(int x) {
    return std::async(f, x).then_futurize(g);
}

() ? ( then_futurize, .)


(Javascript, Python, Ruby, ++ Boost, ++ Folly...); ++, , , .

, .then() X(future<Y>), X(Y); , . , .then() " " .then() , .

+4
2

! N3865 , .then_futurize(); N3865 .next()!

auto async_fg(int x) {
    return std::async(f, x).next(g);
}

N3865 .recover(), Javascript-:

std::future<std::string> f2 = f1.next(
    [](int v) {
        return v.to_string();
    }
).recover(
    [](exception_ptr ex) {
        return "nan";
    }
);

, .has_value() .value_or().

( futurize(), .then_futurize() .next().)

+2

do_next?

template<class F>
auto do_next( F&& f )
{
  return [f = std::forward<F>(f)]( auto&& fut ) {
    return f( decltype(fut)(fut).get() );
  };
}

auto async_fg(int x) {
  return std::async(f, x).then(do_next(g));
}

, , , then(do_next >>= aka bind, .

:

namespace named_operator {
  template<class D>struct make_operator{make_operator(){}};

  template<class T, char, class O> struct half_apply { T&& lhs; };

  template<class Lhs, class Op>
  half_apply<Lhs, '*', Op> operator*( Lhs&& lhs, make_operator<Op> ) {
      return {std::forward<Lhs>(lhs)};
  }

  template<class Lhs, class Op, class Rhs>
  auto operator*( half_apply<Lhs, '*', Op>&& lhs, Rhs&& rhs )
  -> decltype( invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) ) )
  {
      return invoke( std::forward<Lhs>(lhs.lhs), Op{}, std::forward<Rhs>(rhs) );
  }
}

namespace my_operator {
  struct do_next_t{};
  static const named_operator<do_next_t> do_next;

  template<class T, class F,
    class R = std::result_of_t<std::decay_t<F>(T)>
  >
  auto invoke( std::future<T>&& lhs, do_next_t, F&& f )
  -> std::future< R >
  {
    return lhs.then( [f = std::forward<F>(f)](std::future<T> fut)mutable->R {
      return std::move(f)(std::forward<F>(fut.get()));
    });
  };
}
using my_operator::do_next;

:

auto async_fg(int x) {
  return std::async(f, x) *do_next* g;
}

, *then_do*.

( . then).

...

Haskell, , .then fmap, .then(futurize >>= bind , , futurize lift .

>>= bind , fmap/lift; , .

0

All Articles