[英]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.