Implement continuable_base<...>::as

* Can convert continuables to other compatible signatures
This commit is contained in:
Denis Blank 2018-12-25 13:24:34 +01:00
parent 30f0dca27f
commit 7a10363dce
3 changed files with 65 additions and 2 deletions

View File

@ -404,6 +404,24 @@ public:
std::forward<E>(executor)); std::forward<E>(executor));
} }
/// Returns a continuable_base which will have its signature converted
/// to the given Args.
///
/// A signature can only be converted if it can be partially applied
/// from the previous one as shown below:
/// ```cpp
/// continuable<long> c = make_ready_continuable(0, 1, 2).as<long>();
/// ```
///
/// \returns Returns a continuable_base with an asynchronous return type
/// matching the given Args.
///
/// \since 4.0.0
template <typename... Args>
auto as() && {
return std::move(*this).then(detail::base::convert_to<Args...>{});
}
/// A method which allows to apply this continuable to the given callable. /// A method which allows to apply this continuable to the given callable.
/// ///
/// \param transform A transform which shall accept this continuable /// \param transform A transform which shall accept this continuable

View File

@ -473,8 +473,10 @@ void on_executor(Executor&& executor, Invoker&& invoker, Args&&... args) {
// Create a worker object which when invoked calls the callback with the // Create a worker object which when invoked calls the callback with the
// the returned arguments. // the returned arguments.
auto work = [invoker = std::forward<Invoker>(invoker), auto work = [
args = std::make_tuple(std::forward<Args>(args)...)]() mutable { invoker = std::forward<Invoker>(invoker),
args = std::make_tuple(std::forward<Args>(args)...)
]() mutable {
traits::unpack( traits::unpack(
[&](auto&&... captured_args) { [&](auto&&... captured_args) {
// Just use the packed dispatch method which dispatches the work on // Just use the packed dispatch method which dispatches the work on
@ -915,6 +917,25 @@ auto wrap_continuation(Continuation&& continuation) {
return supplier_callback<std::decay_t<Continuation>>( return supplier_callback<std::decay_t<Continuation>>(
std::forward<Continuation>(continuation)); std::forward<Continuation>(continuation));
} }
/// Callback which converts its input to the given set of arguments
template <typename... Args>
struct convert_to {
std::tuple<Args...> operator()(Args... args) {
return std::make_tuple(std::move(args)...);
}
};
template <typename T>
struct convert_to<T> {
T operator()(T arg) noexcept {
return std::move(arg);
}
};
template <>
struct convert_to<> {
void operator()() noexcept {
}
};
} // namespace base } // namespace base
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -60,3 +60,27 @@ TYPED_TEST(single_dimension_tests, are_continuing_chainable) {
ASSERT_ASYNC_TYPES(std::move(chain), tag1); ASSERT_ASYNC_TYPES(std::move(chain), tag1);
} }
TYPED_TEST(single_dimension_tests, are_converted_chainable_0) {
auto chain =
this->supply().then([&] { return this->supply(tag1{}).template as<>(); });
ASSERT_ASYNC_COMPLETION(std::move(chain).then([](auto&&... args) {
ASSERT_EQ(sizeof...(args), 0U); //
}));
}
TYPED_TEST(single_dimension_tests, are_converted_chainable_1) {
auto chain = this->supply().then(
[&] { return this->supply(float(0)).template as<double>(); });
ASSERT_ASYNC_TYPES(std::move(chain), double);
}
TYPED_TEST(single_dimension_tests, are_converted_chainable_2) {
auto chain = this->supply().then([&] {
return this->supply(int(0), float(0)).template as<long, double>();
});
ASSERT_ASYNC_TYPES(std::move(chain), long, double);
}