簡體   English   中英

圍繞std :: future :: then有這個便利包裝的名稱嗎?

[英]Is there a name for this convenience wrapper around std::future::then?

jQuery版本的“Deferreds” (C ++稱之為“期貨”)中, .then()方法將一個函數作為其參數,其簽名不包含任何未來。 然而,為C ++ 17( 參見N3721 .then()提出的.then( )在其簽名中采用了具有future的函數。

即,如果我想在后台計算f(g(x)) “,N3721希望我寫

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());
    });
}

我很想寫一個包裝器,像這樣:

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));
}

但是,這兩種解決方案看起來都很尷 除此之外,我不知道我在這里稱之為“未來化”的操作的正確名稱 如果之前已經提出過此操作,那么有人稱它為何?


顯然,如果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了名稱then_futurize ,我不喜歡它。)


我會接受任何現有語言或庫的答案(Javascript,Python,Ruby,C ++ Boost,C ++ Folly ......); 它們不一定是專門的C ++標准提案,盡管顯然這是最好的。

我已經注意到, 愚蠢的版本.then()需要一個函數簽名或者 X(future<Y>) X(Y) ; 但我想這會在一些極端情況下變得模棱兩可。 此外,未來的.then()和“便利包裝” .then()似乎是完全不同的操作,我更喜歡它們的不同名稱。

啊哈! 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() 。)

do_next怎么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));
}

如上所述,將未來視為Haskell monad,然后我認為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,我認為。然后是fmap on fmap .then fmap .then(futurize>>=bind monad,這意味着futurize是對functor的lift

>>=bind通常被認為比fmap / lift更容易使用; 將這兩者組合成一個概念。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM