2 * Copyright 2015 Facebook, Inc.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
22 #include <folly/experimental/fibers/Baton.h>
23 #include <folly/Optional.h>
24 #include <folly/futures/detail/Core.h>
25 #include <folly/futures/Timekeeper.h>
32 Timekeeper* getTimekeeperSingleton();
36 Future<T>::Future(Future<T>&& other) noexcept : core_(other.core_) {
37 other.core_ = nullptr;
41 Future<T>& Future<T>::operator=(Future<T>&& other) noexcept {
42 std::swap(core_, other.core_);
48 typename std::enable_if<!isFuture<T2>::value, void*>::type>
49 Future<T>::Future(T2&& val) : core_(nullptr) {
51 p.setValue(std::forward<T2>(val));
52 *this = p.getFuture();
57 typename std::enable_if<
58 folly::is_void_or_unit<T2>::value,
60 Future<T>::Future() : core_(nullptr) {
63 *this = p.getFuture();
68 Future<T>::~Future() {
73 void Future<T>::detach() {
75 core_->detachFuture();
81 void Future<T>::throwIfInvalid() const {
88 void Future<T>::setCallback_(F&& func) {
90 core_->setCallback(std::move(func));
97 typename std::enable_if<isFuture<F>::value,
98 Future<typename isFuture<T>::Inner>>::type
100 return then([](Future<typename isFuture<T>::Inner> internal_future) {
101 return internal_future;
107 // Variant: returns a value
108 // e.g. f.then([](Try<T>&& t){ return t.value(); });
110 template <typename F, typename R, bool isTry, typename... Args>
111 typename std::enable_if<!R::ReturnsFuture::value, typename R::Return>::type
112 Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
113 static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
114 typedef typename R::ReturnsFuture::Inner B;
118 // wrap these so we can move them into the lambda
119 folly::MoveWrapper<Promise<B>> p;
120 folly::MoveWrapper<F> funcm(std::forward<F>(func));
122 // grab the Future now before we lose our handle on the Promise
123 auto f = p->getFuture();
125 f.setExecutor(getExecutor());
128 /* This is a bit tricky.
130 We can't just close over *this in case this Future gets moved. So we
131 make a new dummy Future. We could figure out something more
132 sophisticated that avoids making a new Future object when it can, as an
133 optimization. But this is correct.
135 core_ can't be moved, it is explicitly disallowed (as is copying). But
136 if there's ever a reason to allow it, this is one place that makes that
137 assumption and would need to be fixed. We use a standard shared pointer
138 for core_ (by copying it in), which means in essence obj holds a shared
139 pointer to itself. But this shouldn't leak because Promise will not
140 outlive the continuation, because Promise will setException() with a
141 broken Promise if it is destructed before completed. We could use a
142 weak pointer but it would have to be converted to a shared pointer when
143 func is executed (because the Future returned by func may possibly
144 persist beyond the callback, if it gets moved), and so it is an
145 optimization to just make it shared from the get-go.
147 We have to move in the Promise and func using the MoveWrapper
148 hack. (func could be copied but it's a big drag on perf).
150 Two subtle but important points about this design. detail::Core has no
151 back pointers to Future or Promise, so if Future or Promise get moved
152 (and they will be moved in performant code) we don't have to do
153 anything fancy. And because we store the continuation in the
154 detail::Core, not in the Future, we can execute the continuation even
155 after the Future has gone out of scope. This is an intentional design
156 decision. It is likely we will want to be able to cancel a continuation
157 in some circumstances, but I think it should be explicit not implicit
158 in the destruction of the Future used to create it.
161 [p, funcm](Try<T>&& t) mutable {
162 if (!isTry && t.hasException()) {
163 p->setException(std::move(t.exception()));
166 return (*funcm)(t.template get<isTry, Args>()...);
174 // Variant: returns a Future
175 // e.g. f.then([](T&& t){ return makeFuture<T>(t); });
177 template <typename F, typename R, bool isTry, typename... Args>
178 typename std::enable_if<R::ReturnsFuture::value, typename R::Return>::type
179 Future<T>::thenImplementation(F func, detail::argResult<isTry, F, Args...>) {
180 static_assert(sizeof...(Args) <= 1, "Then must take zero/one argument");
181 typedef typename R::ReturnsFuture::Inner B;
185 // wrap these so we can move them into the lambda
186 folly::MoveWrapper<Promise<B>> p;
187 folly::MoveWrapper<F> funcm(std::forward<F>(func));
189 // grab the Future now before we lose our handle on the Promise
190 auto f = p->getFuture();
192 f.setExecutor(getExecutor());
196 [p, funcm](Try<T>&& t) mutable {
197 if (!isTry && t.hasException()) {
198 p->setException(std::move(t.exception()));
201 auto f2 = (*funcm)(t.template get<isTry, Args>()...);
202 // that didn't throw, now we can steal p
203 f2.setCallback_([p](Try<B>&& b) mutable {
204 p->setTry(std::move(b));
206 } catch (const std::exception& e) {
207 p->setException(exception_wrapper(std::current_exception(), e));
209 p->setException(exception_wrapper(std::current_exception()));
217 template <typename T>
218 template <typename R, typename Caller, typename... Args>
219 Future<typename isFuture<R>::Inner>
220 Future<T>::then(R(Caller::*func)(Args...), Caller *instance) {
221 typedef typename std::remove_cv<
222 typename std::remove_reference<
223 typename detail::ArgType<Args...>::FirstArg>::type>::type FirstArg;
224 return then([instance, func](Try<T>&& t){
225 return (instance->*func)(t.template get<isTry<FirstArg>::value, Args>()...);
232 template <class... Args>
233 auto Future<T>::then(Executor* x, Args&&... args)
234 -> decltype(this->then(std::forward<Args>(args)...))
236 auto oldX = getExecutor();
238 return this->then(std::forward<Args>(args)...).via(oldX);
243 Future<void> Future<T>::then() {
244 return then([] (Try<T>&& t) {});
247 // onError where the callback returns T
250 typename std::enable_if<
251 !detail::callableWith<F, exception_wrapper>::value &&
252 !detail::Extract<F>::ReturnsFuture::value,
254 Future<T>::onError(F&& func) {
255 typedef typename detail::Extract<F>::FirstArg Exn;
257 std::is_same<typename detail::Extract<F>::RawReturn, T>::value,
258 "Return type of onError callback must be T or Future<T>");
261 auto f = p.getFuture();
262 auto pm = folly::makeMoveWrapper(std::move(p));
263 auto funcm = folly::makeMoveWrapper(std::move(func));
264 setCallback_([pm, funcm](Try<T>&& t) mutable {
265 if (!t.template withException<Exn>([&] (Exn& e) {
270 pm->setTry(std::move(t));
277 // onError where the callback returns Future<T>
280 typename std::enable_if<
281 !detail::callableWith<F, exception_wrapper>::value &&
282 detail::Extract<F>::ReturnsFuture::value,
284 Future<T>::onError(F&& func) {
286 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
287 "Return type of onError callback must be T or Future<T>");
288 typedef typename detail::Extract<F>::FirstArg Exn;
291 auto f = p.getFuture();
292 auto pm = folly::makeMoveWrapper(std::move(p));
293 auto funcm = folly::makeMoveWrapper(std::move(func));
294 setCallback_([pm, funcm](Try<T>&& t) mutable {
295 if (!t.template withException<Exn>([&] (Exn& e) {
297 auto f2 = (*funcm)(e);
298 f2.setCallback_([pm](Try<T>&& t2) mutable {
299 pm->setTry(std::move(t2));
301 } catch (const std::exception& e2) {
302 pm->setException(exception_wrapper(std::current_exception(), e2));
304 pm->setException(exception_wrapper(std::current_exception()));
307 pm->setTry(std::move(t));
316 Future<T> Future<T>::ensure(F func) {
317 MoveWrapper<F> funcw(std::move(func));
318 return this->then([funcw](Try<T>&& t) {
320 return makeFuture(std::move(t));
326 Future<T> Future<T>::onTimeout(Duration dur, F&& func, Timekeeper* tk) {
327 auto funcw = folly::makeMoveWrapper(std::forward<F>(func));
328 return within(dur, tk)
329 .onError([funcw](TimedOut const&) { return (*funcw)(); });
334 typename std::enable_if<
335 detail::callableWith<F, exception_wrapper>::value &&
336 detail::Extract<F>::ReturnsFuture::value,
338 Future<T>::onError(F&& func) {
340 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
341 "Return type of onError callback must be T or Future<T>");
344 auto f = p.getFuture();
345 auto pm = folly::makeMoveWrapper(std::move(p));
346 auto funcm = folly::makeMoveWrapper(std::move(func));
347 setCallback_([pm, funcm](Try<T> t) mutable {
348 if (t.hasException()) {
350 auto f2 = (*funcm)(std::move(t.exception()));
351 f2.setCallback_([pm](Try<T> t2) mutable {
352 pm->setTry(std::move(t2));
354 } catch (const std::exception& e2) {
355 pm->setException(exception_wrapper(std::current_exception(), e2));
357 pm->setException(exception_wrapper(std::current_exception()));
360 pm->setTry(std::move(t));
367 // onError(exception_wrapper) that returns T
370 typename std::enable_if<
371 detail::callableWith<F, exception_wrapper>::value &&
372 !detail::Extract<F>::ReturnsFuture::value,
374 Future<T>::onError(F&& func) {
376 std::is_same<typename detail::Extract<F>::Return, Future<T>>::value,
377 "Return type of onError callback must be T or Future<T>");
380 auto f = p.getFuture();
381 auto pm = folly::makeMoveWrapper(std::move(p));
382 auto funcm = folly::makeMoveWrapper(std::move(func));
383 setCallback_([pm, funcm](Try<T> t) mutable {
384 if (t.hasException()) {
386 return (*funcm)(std::move(t.exception()));
389 pm->setTry(std::move(t));
397 typename std::add_lvalue_reference<T>::type Future<T>::value() {
400 return core_->getTry().value();
404 typename std::add_lvalue_reference<const T>::type Future<T>::value() const {
407 return core_->getTry().value();
411 Try<T>& Future<T>::getTry() {
414 return core_->getTry();
418 Optional<Try<T>> Future<T>::poll() {
420 if (core_->ready()) {
421 o = std::move(core_->getTry());
427 template <typename Executor>
428 inline Future<T> Future<T>::via(Executor* executor) && {
431 setExecutor(executor);
433 return std::move(*this);
437 template <typename Executor>
438 inline Future<T> Future<T>::via(Executor* executor) & {
441 MoveWrapper<Promise<T>> p;
442 auto f = p->getFuture();
443 then([p](Try<T>&& t) mutable { p->setTry(std::move(t)); });
444 return std::move(f).via(executor);
448 bool Future<T>::isReady() const {
450 return core_->ready();
454 void Future<T>::raise(exception_wrapper exception) {
455 core_->raise(std::move(exception));
461 Future<typename std::decay<T>::type> makeFuture(T&& t) {
462 Promise<typename std::decay<T>::type> p;
463 p.setValue(std::forward<T>(t));
464 return p.getFuture();
467 inline // for multiple translation units
468 Future<void> makeFuture() {
471 return p.getFuture();
477 typename std::enable_if<!std::is_reference<F>::value, bool>::type sdf)
478 -> Future<decltype(func())> {
479 Promise<decltype(func())> p;
484 return p.getFuture();
488 auto makeFutureWith(F const& func) -> Future<decltype(func())> {
490 return makeFutureWith(std::move(copy));
494 Future<T> makeFuture(std::exception_ptr const& e) {
497 return p.getFuture();
501 Future<T> makeFuture(exception_wrapper ew) {
503 p.setException(std::move(ew));
504 return p.getFuture();
507 template <class T, class E>
508 typename std::enable_if<std::is_base_of<std::exception, E>::value,
510 makeFuture(E const& e) {
512 p.setException(make_exception_wrapper<E>(e));
513 return p.getFuture();
517 Future<T> makeFuture(Try<T>&& t) {
518 Promise<typename std::decay<T>::type> p;
519 p.setTry(std::move(t));
520 return p.getFuture();
524 inline Future<void> makeFuture(Try<void>&& t) {
525 if (t.hasException()) {
526 return makeFuture<void>(std::move(t.exception()));
533 template <typename Executor>
534 Future<void> via(Executor* executor) {
535 return makeFuture().via(executor);
540 template <typename... Fs>
541 typename detail::VariadicContext<
542 typename std::decay<Fs>::type::value_type...>::type
543 collectAll(Fs&&... fs) {
545 new detail::VariadicContext<typename std::decay<Fs>::type::value_type...>();
546 ctx->total = sizeof...(fs);
547 auto f_saved = ctx->p.getFuture();
548 detail::collectAllVariadicHelper(ctx,
549 std::forward<typename std::decay<Fs>::type>(fs)...);
555 template <class InputIterator>
558 Try<typename std::iterator_traits<InputIterator>::value_type::value_type>>>
559 collectAll(InputIterator first, InputIterator last) {
561 typename std::iterator_traits<InputIterator>::value_type::value_type T;
564 return makeFuture(std::vector<Try<T>>());
566 size_t n = std::distance(first, last);
568 auto ctx = new detail::WhenAllContext<T>();
570 ctx->results.resize(n);
572 auto f_saved = ctx->p.getFuture();
574 for (size_t i = 0; first != last; ++first, ++i) {
577 f.setCallback_([ctx, i, n](Try<T> t) {
578 ctx->results[i] = std::move(t);
579 if (++ctx->count == n) {
580 ctx->p.setValue(std::move(ctx->results));
591 template <class, class, typename = void> struct CollectContextHelper;
593 template <class T, class VecT>
594 struct CollectContextHelper<T, VecT,
595 typename std::enable_if<std::is_same<T, VecT>::value>::type> {
596 static inline std::vector<T>&& getResults(std::vector<VecT>& results) {
597 return std::move(results);
601 template <class T, class VecT>
602 struct CollectContextHelper<T, VecT,
603 typename std::enable_if<!std::is_same<T, VecT>::value>::type> {
604 static inline std::vector<T> getResults(std::vector<VecT>& results) {
605 std::vector<T> finalResults;
606 finalResults.reserve(results.size());
607 for (auto& opt : results) {
608 finalResults.push_back(std::move(opt.value()));
614 template <typename T>
615 struct CollectContext {
617 typedef typename std::conditional<
618 std::is_default_constructible<T>::value,
623 explicit CollectContext(int n) : count(0), success_count(0), threw(false) {
627 Promise<std::vector<T>> p;
628 std::vector<VecT> results;
629 std::atomic<size_t> count, success_count;
630 std::atomic_bool threw;
632 typedef std::vector<T> result_type;
634 static inline Future<std::vector<T>> makeEmptyFuture() {
635 return makeFuture(std::vector<T>());
638 inline void setValue() {
639 p.setValue(CollectContextHelper<T, VecT>::getResults(results));
642 inline void addResult(int i, Try<T>& t) {
643 results[i] = std::move(t.value());
648 struct CollectContext<void> {
650 explicit CollectContext(int n) : count(0), success_count(0), threw(false) {}
653 std::atomic<size_t> count, success_count;
654 std::atomic_bool threw;
656 typedef void result_type;
658 static inline Future<void> makeEmptyFuture() {
662 inline void setValue() {
666 inline void addResult(int i, Try<void>& t) {
673 template <class InputIterator>
674 Future<typename detail::CollectContext<
675 typename std::iterator_traits<InputIterator>::value_type::value_type
677 collect(InputIterator first, InputIterator last) {
679 typename std::iterator_traits<InputIterator>::value_type::value_type T;
682 return detail::CollectContext<T>::makeEmptyFuture();
685 size_t n = std::distance(first, last);
686 auto ctx = new detail::CollectContext<T>(n);
687 auto f_saved = ctx->p.getFuture();
689 for (size_t i = 0; first != last; ++first, ++i) {
692 f.setCallback_([ctx, i, n](Try<T> t) {
694 if (t.hasException()) {
695 if (!ctx->threw.exchange(true)) {
696 ctx->p.setException(std::move(t.exception()));
698 } else if (!ctx->threw) {
699 ctx->addResult(i, t);
700 if (++ctx->success_count == n) {
705 if (++ctx->count == n) {
714 template <class InputIterator>
719 std::iterator_traits<InputIterator>::value_type::value_type> > >
720 collectAny(InputIterator first, InputIterator last) {
722 typename std::iterator_traits<InputIterator>::value_type::value_type T;
724 auto ctx = new detail::WhenAnyContext<T>(std::distance(first, last));
725 auto f_saved = ctx->p.getFuture();
727 for (size_t i = 0; first != last; first++, i++) {
729 f.setCallback_([i, ctx](Try<T>&& t) {
730 if (!ctx->done.exchange(true)) {
731 ctx->p.setValue(std::make_pair(i, std::move(t)));
740 template <class InputIterator>
741 Future<std::vector<std::pair<size_t, Try<typename
742 std::iterator_traits<InputIterator>::value_type::value_type>>>>
743 collectN(InputIterator first, InputIterator last, size_t n) {
745 std::iterator_traits<InputIterator>::value_type::value_type T;
746 typedef std::vector<std::pair<size_t, Try<T>>> V;
753 auto ctx = std::make_shared<ctx_t>();
756 // for each completed Future, increase count and add to vector, until we
757 // have n completed futures at which point we fulfill our Promise with the
762 it->then([ctx, n, i](Try<T>&& t) {
764 auto c = ++ctx->completed;
766 assert(ctx->v.size() < n);
767 v.push_back(std::make_pair(i, std::move(t)));
769 ctx->p.setTry(Try<V>(std::move(v)));
779 ctx->p.setException(std::runtime_error("Not enough futures"));
782 return ctx->p.getFuture();
785 template <class It, class T, class F, class ItT, class Arg>
786 typename std::enable_if<!isFutureResult<F, T, Arg>::value, Future<T>>::type
787 reduce(It first, It last, T initial, F func) {
789 return makeFuture(std::move(initial));
792 typedef isTry<Arg> IsTry;
794 return collectAll(first, last)
795 .then([initial, func](std::vector<Try<ItT>>& vals) mutable {
796 for (auto& val : vals) {
797 initial = func(std::move(initial),
798 // Either return a ItT&& or a Try<ItT>&& depending
799 // on the type of the argument of func.
800 val.template get<IsTry::value, Arg&&>());
806 template <class It, class T, class F, class ItT, class Arg>
807 typename std::enable_if<isFutureResult<F, T, Arg>::value, Future<T>>::type
808 reduce(It first, It last, T initial, F func) {
810 return makeFuture(std::move(initial));
813 typedef isTry<Arg> IsTry;
815 auto f = first->then([initial, func](Try<ItT>& head) mutable {
816 return func(std::move(initial),
817 head.template get<IsTry::value, Arg&&>());
820 for (++first; first != last; ++first) {
821 f = collectAll(f, *first).then([func](std::tuple<Try<T>, Try<ItT>>& t) {
822 return func(std::move(std::get<0>(t).value()),
823 // Either return a ItT&& or a Try<ItT>&& depending
824 // on the type of the argument of func.
825 std::get<1>(t).template get<IsTry::value, Arg&&>());
833 Future<T> Future<T>::within(Duration dur, Timekeeper* tk) {
834 return within(dur, TimedOut(), tk);
839 Future<T> Future<T>::within(Duration dur, E e, Timekeeper* tk) {
842 Context(E ex) : exception(std::move(ex)), promise(), token(false) {}
845 std::atomic<bool> token;
847 auto ctx = std::make_shared<Context>(std::move(e));
850 tk = folly::detail::getTimekeeperSingleton();
854 .then([ctx](Try<void> const& t) {
855 if (ctx->token.exchange(true) == false) {
856 if (t.hasException()) {
857 ctx->promise.setException(std::move(t.exception()));
859 ctx->promise.setException(std::move(ctx->exception));
864 this->then([ctx](Try<T>&& t) {
865 if (ctx->token.exchange(true) == false) {
866 ctx->promise.setTry(std::move(t));
870 return ctx->promise.getFuture();
874 Future<T> Future<T>::delayed(Duration dur, Timekeeper* tk) {
875 return collectAll(*this, futures::sleep(dur, tk))
876 .then([](std::tuple<Try<T>, Try<void>> tup) {
877 Try<T>& t = std::get<0>(tup);
878 return makeFuture<T>(std::move(t));
885 void waitImpl(Future<T>& f) {
886 // short-circuit if there's nothing to do
887 if (f.isReady()) return;
889 folly::fibers::Baton baton;
890 f = f.then([&](Try<T> t) {
892 return makeFuture(std::move(t));
896 // There's a race here between the return here and the actual finishing of
897 // the future. f is completed, but the setup may not have finished on done
898 // after the baton has posted.
899 while (!f.isReady()) {
900 std::this_thread::yield();
905 void waitImpl(Future<T>& f, Duration dur) {
906 // short-circuit if there's nothing to do
907 if (f.isReady()) return;
909 auto baton = std::make_shared<folly::fibers::Baton>();
910 f = f.then([baton](Try<T> t) {
912 return makeFuture(std::move(t));
915 // Let's preserve the invariant that if we did not timeout (timed_wait returns
916 // true), then the returned Future is complete when it is returned to the
917 // caller. We need to wait out the race for that Future to complete.
918 if (baton->timed_wait(dur)) {
919 while (!f.isReady()) {
920 std::this_thread::yield();
926 void waitViaImpl(Future<T>& f, DrivableExecutor* e) {
927 while (!f.isReady()) {
935 Future<T>& Future<T>::wait() & {
936 detail::waitImpl(*this);
941 Future<T>&& Future<T>::wait() && {
942 detail::waitImpl(*this);
943 return std::move(*this);
947 Future<T>& Future<T>::wait(Duration dur) & {
948 detail::waitImpl(*this, dur);
953 Future<T>&& Future<T>::wait(Duration dur) && {
954 detail::waitImpl(*this, dur);
955 return std::move(*this);
959 Future<T>& Future<T>::waitVia(DrivableExecutor* e) & {
960 detail::waitViaImpl(*this, e);
965 Future<T>&& Future<T>::waitVia(DrivableExecutor* e) && {
966 detail::waitViaImpl(*this, e);
967 return std::move(*this);
972 return std::move(wait().value());
976 inline void Future<void>::get() {
981 T Future<T>::get(Duration dur) {
984 return std::move(value());
991 inline void Future<void>::get(Duration dur) {
1001 T Future<T>::getVia(DrivableExecutor* e) {
1002 return std::move(waitVia(e).value());
1006 inline void Future<void>::getVia(DrivableExecutor* e) {
1011 Future<bool> Future<T>::willEqual(Future<T>& f) {
1012 return collectAll(*this, f).then([](const std::tuple<Try<T>, Try<T>>& t) {
1013 if (std::get<0>(t).hasValue() && std::get<1>(t).hasValue()) {
1014 return std::get<0>(t).value() == std::get<1>(t).value();
1023 Future<T> Future<T>::filter(F predicate) {
1024 auto p = folly::makeMoveWrapper(std::move(predicate));
1025 return this->then([p](T val) {
1026 T const& valConstRef = val;
1027 if (!(*p)(valConstRef)) {
1028 throw PredicateDoesNotObtain();
1037 Future<Z> chainHelper(Future<Z> f) {
1041 template <class Z, class F, class Fn, class... Callbacks>
1042 Future<Z> chainHelper(F f, Fn fn, Callbacks... fns) {
1043 return chainHelper<Z>(f.then(fn), fns...);
1047 template <class A, class Z, class... Callbacks>
1048 std::function<Future<Z>(Try<A>)>
1049 chain(Callbacks... fns) {
1050 MoveWrapper<Promise<A>> pw;
1051 MoveWrapper<Future<Z>> fw(chainHelper<Z>(pw->getFuture(), fns...));
1052 return [=](Try<A> t) mutable {
1053 pw->setTry(std::move(t));
1054 return std::move(*fw);
1058 template <class It, class F, class ItT, class Result>
1059 std::vector<Future<Result>> map(It first, It last, F func) {
1060 std::vector<Future<Result>> results;
1061 for (auto it = first; it != last; it++) {
1062 results.push_back(it->then(func));
1068 } // namespace folly
1070 // I haven't included a Future<T&> specialization because I don't forsee us
1071 // using it, however it is not difficult to add when needed. Refer to
1072 // Future<void> for guidance. std::future and boost::future code would also be