Summary:
I have half a mind to just rip this out and let people use std::bind if they need this. But I won't be so cruel.
Why isn't this just implemented as `then(std::bind(method, object))` anyway? Is the template soup we have now faster?
Test Plan:
Fixed the unit tests to use the new format.
Will look to contbuild to catch all the things this might break (if anyone is using it at all?), and will fix them.
Reviewed By: hannesr@fb.com
Subscribers: trunkagent, exa, folly-diffs@, yfeldblum, jsedgwick, davejwatson
FB internal diff:
D1831118
Signature: t1:
1831118:
1423243771:
65db9a89daf14d8bd88331c503ba1ea7ab03b679
-template <typename Caller, typename R, typename... Args>
+template <typename R, typename Caller, typename... Args>
Future<typename isFuture<R>::Inner>
Future<typename isFuture<R>::Inner>
-Future<T>::then(Caller *instance, R(Caller::*func)(Args...)) {
+Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
typedef typename std::remove_cv<
typename std::remove_reference<
typename detail::ArgType<Args...>::FirstArg>::type>::type FirstArg;
typedef typename std::remove_cv<
typename std::remove_reference<
typename detail::ArgType<Args...>::FirstArg>::type>::type FirstArg;
/// Variant where func is an member function
///
/// Variant where func is an member function
///
- /// struct Worker {
- /// R doWork(Try<T>&&); }
+ /// struct Worker { R doWork(Try<T>); }
- /// Future<R> f2 = f1.then(w, &Worker::doWork);
- template <typename Caller, typename R, typename... Args>
- Future<typename isFuture<R>::Inner>
- then(Caller *instance, R(Caller::*func)(Args...));
+ /// Future<R> f2 = f1.then(&Worker::doWork, w);
+ ///
+ /// This is just sugar for
+ ///
+ /// f1.then(std::bind(&Worker::doWork, w));
+ template <typename R, typename Caller, typename... Args>
+ Future<typename isFuture<R>::Inner>
+ then(R(Caller::*func)(Args...), Caller *instance);
/// Convenience method for ignoring the value and creating a Future<void>.
/// Exceptions still propagate.
/// Convenience method for ignoring the value and creating a Future<void>.
/// Exceptions still propagate.
auto f = makeFuture<string>("start")
.then(doWorkStatic)
.then(Worker::doWorkStatic)
auto f = makeFuture<string>("start")
.then(doWorkStatic)
.then(Worker::doWorkStatic)
- .then(&w, &Worker::doWork);
+ .then(&Worker::doWork, &w);
EXPECT_EQ(f.value(), "start;static;class-static;class");
}
EXPECT_EQ(f.value(), "start;static;class-static;class");
}
auto f = makeFuture<string>("start")
.then(doWorkStaticFuture)
.then(Worker::doWorkStaticFuture)
auto f = makeFuture<string>("start")
.then(doWorkStaticFuture)
.then(Worker::doWorkStaticFuture)
- .then(&w, &Worker::doWorkFuture);
+ .then(&Worker::doWorkFuture, &w);
EXPECT_EQ(f.value(), "start;static;class-static;class");
}
EXPECT_EQ(f.value(), "start;static;class-static;class");
}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&&>);}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>&&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A> const&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A> const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A> const&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A> const&>());}
{Future<B> f = someFuture<A>().then([&](Try<A> const&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A> const&>());}
{Future<B> f = someFuture<A>().then([&](Try<A> const&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A>>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>>());}
{Future<B> f = someFuture<A>().then([&](Try<A>){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>>());}
{Future<B> f = someFuture<A>().then([&](Try<A>){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, Try<A>&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, Try<A>&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, Try<A>&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, Try<A>&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, Try<A>&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, A&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A&&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&&>());}
{Future<B> f = someFuture<A>().then([&](A&&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A const&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&&>());}
{Future<B> f = someFuture<A>().then([&](A&&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A const&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, A const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A const&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A const&>());}
{Future<B> f = someFuture<A>().then([&](A const&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A const&>());}
{Future<B> f = someFuture<A>().then([&](A const&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, A>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A>());}
{Future<B> f = someFuture<A>().then([&](A){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A>());}
{Future<B> f = someFuture<A>().then([&](A){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<Future<B>, A&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<Future<B>, A&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<Future<B>, A&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<Future<B>, A&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&>());}
{Future<B> f = someFuture<A>().then([&](A&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then([&](){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<Future<B>, A&>());}
{Future<B> f = someFuture<A>().then([&](A&){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then([&](){return someFuture<B>();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A>&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>&&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A> const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A> const&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A> const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A> const&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A> const&>());}
{Future<B> f = someFuture<A>().then([&](Try<A> const&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A> const&>());}
{Future<B> f = someFuture<A>().then([&](Try<A> const&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A>>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>>());}
{Future<B> f = someFuture<A>().then([&](Try<A>){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>>());}
{Future<B> f = someFuture<A>().then([&](Try<A>){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, Try<A>&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, Try<A>&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, Try<A>&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, Try<A>&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, Try<A>&>());}
{Future<B> f = someFuture<A>().then([&](Try<A>&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A&&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, A&&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A&&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A&&>());}
{Future<B> f = someFuture<A>().then([&](A&&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A const&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A&&>());}
{Future<B> f = someFuture<A>().then([&](A&&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A const&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A const&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, A const&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A const&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A const&>());}
{Future<B> f = someFuture<A>().then([&](A const&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A const&>());}
{Future<B> f = someFuture<A>().then([&](A const&){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, A>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A>());}
{Future<B> f = someFuture<A>().then([&](A){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&>);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A>());}
{Future<B> f = someFuture<A>().then([&](A){return B();});}
{Future<B> f = someFuture<A>().then(&aFunction<B, A&>);}
{Future<B> f = someFuture<A>().then(&SomeClass::aStaticMethod<B, A&>);}
- {Future<B> f = someFuture<A>().then(&anObject, &SomeClass::aMethod<B, A&>);}
+ {Future<B> f = someFuture<A>().then(&SomeClass::aMethod<B, A&>, &anObject);}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A&>());}
{Future<B> f = someFuture<A>().then([&](A&){return B();});}
{Future<B> f = someFuture<A>().then([&](){return B();});}
{Future<B> f = someFuture<A>().then(aStdFunction<B, A&>());}
{Future<B> f = someFuture<A>().then([&](A&){return B();});}
{Future<B> f = someFuture<A>().then([&](){return B();});}
auto f = makeFuture(std::string("start"))
.then(doWorkStatic)
.then(Worker::doWorkStatic)
auto f = makeFuture(std::string("start"))
.then(doWorkStatic)
.then(Worker::doWorkStatic)
- .then(&w, &Worker::doWork)
+ .then(&Worker::doWork, &w)
;
EXPECT_EQ(f.value(), "start;static;class-static;class");
;
EXPECT_EQ(f.value(), "start;static;class-static;class");
[
["&aFunction<#{both}>"],
["&SomeClass::aStaticMethod<#{both}>"],
[
["&aFunction<#{both}>"],
["&SomeClass::aStaticMethod<#{both}>"],
- # TODO switch these around (std::bind-style)
- ["&anObject", "&SomeClass::aMethod<#{both}>"],
+ ["&SomeClass::aMethod<#{both}>", "&anObject"],
["aStdFunction<#{both}>()"],
["[&](#{param}){return #{retval(ret)};}"],
]
["aStdFunction<#{both}>()"],
["[&](#{param}){return #{retval(ret)};}"],
]