diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index c09028e..b1d8d2e 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -491,19 +491,14 @@ public: /// callback once with the first result available. /// /// \param right The continuable on the right-hand side to connect. - /// The right continuable is required to have a compatible - /// result to the left connected continuable_base, - /// such that `std::common_type_t` deduces to - /// a variable for every type in the result of the left and - /// the right continuable_base. + /// The right continuable is required to have the same + /// result as the left connected continuable_base. /// /// \returns Returns a continuable_base with a result type matching /// the combined result which of all connected /// continuable_base objects. - /// The combined result is evaluated through the `std::common_type` - /// trait which returns the type all types can be converted to. /// The returned continuable_base will be in an intermediate lazy - /// state, further calls to its continuable_base::operator && + /// state, further calls to its continuable_base::operator || /// will add other continuable_base objects to the current /// invocation chain. /// ```cpp diff --git a/include/continuable/continuable-compositions.hpp b/include/continuable/continuable-compositions.hpp index 0171f5b..d8a290d 100644 --- a/include/continuable/continuable-compositions.hpp +++ b/include/continuable/continuable-compositions.hpp @@ -179,20 +179,71 @@ auto when_seq(Iterator begin, Iterator end) { return when_seq(detail::range::persist_range(begin, end)); } -/// Connects the given continuables with an *any* logic. +/// Connects the given arguments with an any logic. +/// All continuables contained inside the given nested pack are +/// invoked at once. On completion of one continuable the final handler +/// is called with the result of the resolved continuable. /// -/// \param continuables The continuable_base objects to connect. -/// Requires at least 2 objects to connect. +/// \param args Arbitrary arguments which are connected. +/// Every type is allowed as arguments, continuables may be +/// contained inside tuple like types (`std::tuple`) +/// or in homogeneous containers such as `std::vector`. +/// Non continuable arguments are preserved and passed +/// to the final result as shown below: +/// ```cpp +/// cti::when_any( +/// cti::make_ready_continuable(0, 1), +/// 2, //< See this plain value +/// std::vector>{cti::make_ready_continuable(3), +/// cti::make_ready_continuable(4)}, +/// std::make_tuple(std::make_tuple(cti::make_ready_continuable(5)))) +/// .then([](int r0) { +/// // ... +/// }); +/// ``` /// -/// \see continuable_base::operator|| for details. +/// \see continuable_base::operator|| for details. /// -/// \since 1.1.0 -template -auto when_any(Continuables&&... continuables) { - static_assert(sizeof...(continuables) >= 2, - "Requires at least 2 continuables!"); - return CONTINUABLE_FOLD_EXPRESSION( - ||, std::forward(continuables)...); +/// \since 1.1.0 +template +auto when_any(Args&&... args) { + return detail::composition::apply_composition( + detail::composition::composition_strategy_any_tag{}, + std::forward(args)...); +} + +/// Connects the given arguments with an any logic. +/// The content of the iterator is moved out and converted +/// to a temporary `std::vector` which is then passed to when_all. +/// +/// ```cpp +/// std::vector> v{cti::make_ready_continuable(0), +/// cti::make_ready_continuable(1)}; +/// +/// cti::when_any(v.begin(), v.end()) +/// .then([](int r01) { +/// // ... +/// }); +/// ``` +/// +/// \param begin The begin iterator to the range which will be moved out +/// and used as the arguments to the all connection +/// +/// \param end The end iterator to the range which will be moved out +/// and used as the arguments to the all connection +/// +/// \see when_any for details. +/// +/// \attention Prefer to invoke when_any with the whole container the +/// iterators were taken from, since this saves us +/// the creation of a temporary storage. +/// +/// \since 3.0.0 +template < + typename Iterator, + std::enable_if_t::value>* = nullptr> +auto when_any(Iterator begin, Iterator end) { + return when_any(detail::range::persist_range(begin, end)); } } // namespace cti diff --git a/test/playground/test-playground.cpp b/test/playground/test-playground.cpp index 43f6b89..3f3e069 100644 --- a/test/playground/test-playground.cpp +++ b/test/playground/test-playground.cpp @@ -124,7 +124,7 @@ void old() { int main(int, char**) { using namespace cti::detail; - /*cti::when_seq( + cti::when_seq( cti::make_ready_continuable(0, 1), 2, //< See this plain value std::vector>{cti::make_ready_continuable(3), cti::make_ready_continuable(4)}, @@ -167,11 +167,10 @@ int main(int, char**) { std::tuple> r5) { // ... util::unused(r0, r1, r2, r34, r5); - });*/ + }); - composition::apply_composition(composition::composition_strategy_any_tag{}, - cti::make_ready_continuable(22), - cti::make_ready_continuable(44)) + cti::when_any(cti::make_ready_continuable(22), + cti::make_ready_continuable(44)) .then([](int) { });