diff --git a/doc/code/slideshow/doc-slideshow.cpp b/doc/code/slideshow/doc-slideshow.cpp index 9b98d1f..bc53ab6 100644 --- a/doc/code/slideshow/doc-slideshow.cpp +++ b/doc/code/slideshow/doc-slideshow.cpp @@ -25,27 +25,27 @@ #include "continuable/continuable.hpp" cti::continuable http_request(std::string /*url*/) { - return cti::make_continuable([](auto&& callback) { + return [](auto&& callback) { // ... callback.set_value("..."); - }); + }; } struct ResultSet {}; struct Buffer {}; cti::continuable mysql_query(std::string /*url*/) { - return cti::make_continuable([](auto&& callback) { + return [](auto&& callback) { // ... callback.set_value(ResultSet{}); - }); + }; } cti::continuable read_file(std::string /*url*/) { - return cti::make_continuable([](auto&& callback) { + return [](auto&& callback) { // ... callback.set_value(Buffer{}); - }); + }; } struct a { diff --git a/include/continuable/continuable-base.hpp b/include/continuable/continuable-base.hpp index d1b3140..09d05d4 100644 --- a/include/continuable/continuable-base.hpp +++ b/include/continuable/continuable-base.hpp @@ -167,7 +167,7 @@ public: /// ``` /// /// \param executor The optional executor which is used to dispatch - /// the callback. The executor needs to accept functional objects + /// the callback. The executor needs to accept callable objects /// callable through an `operator()` through its operator() itself. /// The executor can be move-only, but it's not required to. /// The default executor which is used when omitting the argument @@ -634,29 +634,30 @@ private: /// std::forward(callback)(); /// }); /// ``` -/// * **No arguments** indicate that the types are unknown. +/// * **No arguments** Since version 3.0.0 make_continuable always requires +/// to be given valid arguments! /// You should always give the type hint a callback is called with because /// it's required for intermediate actions like connecting continuables. /// You may omit the signature hint if you are erasing the type of /// the continuable right after creation. /// ```cpp -/// // Never do this: +/// // This won't work because the arguments are missing: /// auto ct = cti::make_continuable([](auto&& callback) { /// std::forward(callback)(0.f, 'c'); /// }); /// -/// // However, you may do this: -/// continuable ct = cti::make_continuable([](auto&& callback) { +/// // However, you are allowed to do this: +/// continuable ct = [](auto&& callback) { /// std::forward(callback)(0.f, 'c'); -/// }); +/// }; /// ``` /// /// \param continuation The continuation the continuable is created from. -/// The continuation must be a functional type accepting a callback parameter +/// The continuation must be a callable type accepting a callback parameter /// which represents the object invokable with the asynchronous result of this /// continuable. /// ```cpp -/// auto ct = cti::make_continuable([](auto&& promise) { +/// auto ct = cti::make_continuable([](auto&& promise) { /// promise.set_value("result"); /// }); /// ``` @@ -666,11 +667,11 @@ private: /// It's recommended to accept any callback instead of erasing it. /// ```cpp /// // Good practice: -/// auto ct = cti::make_continuable([](auto&& promise) { +/// auto ct = cti::make_continuable([](auto&& promise) { /// promise.set_value("result"); /// }); /// -/// // Good practice using a functional object: +/// // Good practice using a callable object: /// struct Continuation { /// template /// void operator() (T&& continuation) && { @@ -678,10 +679,10 @@ private: /// } /// } /// -/// auto ct = cti::make_continuable(Continuation{}); +/// auto ct = cti::make_continuable(Continuation{}); /// /// // Bad practice (because of unnecessary type erasure): -/// auto ct = cti::make_continuable( +/// auto ct = cti::make_continuable( /// [](cti::promise promise) { /// promise.set_value("result"); /// }); @@ -698,12 +699,15 @@ private: /// \since 1.0.0 template auto make_continuable(Continuation&& continuation) { - auto hint = detail::composition::annotating::extract( - detail::traits::identity_of(continuation), - detail::traits::identity{}); + static_assert(sizeof...(Args) > 0, + "Since version 3.0.0 make_continuable requires an exact " + "signature! If you did intend to create a void continuable " + "use make_continuable(...). Continuables with an exact " + "signature may be created through make_continuable."); return detail::base::attorney::create( - std::forward(continuation), hint, + std::forward(continuation), + detail::hints::extract(detail::traits::identity{}), detail::util::ownership{}); } diff --git a/include/continuable/detail/base.hpp b/include/continuable/detail/base.hpp index e2c0836..5656470 100644 --- a/include/continuable/detail/base.hpp +++ b/include/continuable/detail/base.hpp @@ -71,7 +71,7 @@ struct is_continuable> : std::true_type {}; /// the continuable_base class. struct attorney { /// Makes a continuation wrapper from the given argument - template + template static auto create(T&& continuation, A /*hint*/, util::ownership ownership_) { return continuable_base, std::decay_t>( std::forward(continuation), ownership_); @@ -107,7 +107,7 @@ struct attorney { // Returns the invoker of a callback, the next callback // and the arguments of the previous continuation. // -// The return type of the invokerOf function matches a functional of: +// The return type of the invokerOf function matches a callable of: // void(auto&& callback, auto&& next_callback, auto&&... args) // // The invoker decorates the result type in the following way @@ -285,7 +285,7 @@ void packed_dispatch(Executor&& executor, Invoker&& invoker, Args&&... args) { }); }; - // Pass the work functional object to the executor + // Pass the work callable object to the executor std::forward(executor)(std::move(work)); } @@ -568,7 +568,7 @@ public: } }; -/// Returns a continuable into a functional object returning the continuable +/// Returns a continuable into a callable object returning the continuable template auto wrap_continuation(Continuation&& continuation) { continuation.freeze(); diff --git a/include/continuable/detail/composition.hpp b/include/continuable/detail/composition.hpp index 41730f5..1fac3b2 100644 --- a/include/continuable/detail/composition.hpp +++ b/include/continuable/detail/composition.hpp @@ -59,53 +59,7 @@ struct is_strategy : std::true_type {}; template <> struct is_strategy : std::true_type {}; -/// Provides support for extracting the signature hint out -/// of given types and parameters. -namespace annotating { -namespace detail { -/// Void hints are equal to an empty signature -constexpr auto make_hint_of(traits::identity) noexcept { - return hints::signature_hint_tag<>{}; -} -/// All other hints are the obvious hints... -template -constexpr auto make_hint_of(traits::identity args) noexcept { - return args; // Identity is equal to signature_hint_tag -} -} // namespace detail - -/// Extracts the signature hint of a given continuation and it's optional -/// present hint arguments. -/// -/// There are 3 cases: -/// - Any argument is given: -/// -> The hint is of the argument type where void is equal to no args -/// - An unwrappable type is given which first arguments signature is known -/// -> The hint is of the mentioned signature -/// - An object which signature isn't known -/// -> The hint is unknown -/// -/// In any cases the return type is a: -/// - signature_hint_tag or a -/// - absent_signature_hint_tag -/// -template -constexpr auto extract(traits::identity /*type*/, - traits::identity hint) { - return traits::static_if(hint, traits::is_empty(), - [=](auto /*hint*/) { - /// When the arguments are the hint is absent - return hints::absent_signature_hint_tag{}; - }, - [](auto hint) { - // When hint arguments are given just take it as - // hint - return detail::make_hint_of(hint); - }); -} -} // namespace annotating - -namespace detail { + namespace detail { template constexpr void assign(traits::size_constant /*pos*/, T& /*storage*/) { // ... diff --git a/include/continuable/detail/hints.hpp b/include/continuable/detail/hints.hpp index 6975ecc..25079c3 100644 --- a/include/continuable/detail/hints.hpp +++ b/include/continuable/detail/hints.hpp @@ -42,28 +42,28 @@ namespace hints { /// Represents a present signature hint template using signature_hint_tag = traits::identity; -/// Represents an absent signature hint -struct absent_signature_hint_tag {}; -template -struct is_absent_hint : std::false_type {}; -template <> -struct is_absent_hint : std::true_type {}; - -/// Returns the signature hint of the given continuable -template -constexpr auto hint_of(traits::identity) { - static_assert(traits::fail::value, - "Expected a continuation with an existing signature hint!"); - return traits::identity{}; -} /// Returns the signature hint of the given continuable template constexpr auto -hint_of(traits::identity< - continuable_base>>) { +hint_of(traits::identity>>) { return hints::signature_hint_tag{}; } + +/// Extracts the signature we pass to the internal continuable +/// from an argument pack as specified by make_continuable. +/// +/// This is the overload taking an arbitrary amount of args +template +constexpr auto extract(traits::identity hint) { + return hint; +} +/// \copybrief extract +/// +/// This is the overload taking a void arg. +constexpr auto extract(traits::identity /*hint*/) { + return traits::identity<>{}; +} } // namespace hints } // namespace detail } // namespace cti diff --git a/include/continuable/detail/traits.hpp b/include/continuable/detail/traits.hpp index 84bb7bb..fb12337 100644 --- a/include/continuable/detail/traits.hpp +++ b/include/continuable/detail/traits.hpp @@ -254,7 +254,7 @@ constexpr auto is_valid(T&& /*type*/, Check&& /*check*/) noexcept { return typename detail::is_valid_impl::type{}; } -/// Creates a static functional validator object. +/// Creates a static callable validation object. template constexpr auto validator_of(Check&& check) noexcept( std::is_nothrow_move_constructible>::value) { diff --git a/test/unit-test/multi/test-continuable-erasure.cpp b/test/unit-test/multi/test-continuable-erasure.cpp index 89d1257..c74ce2c 100644 --- a/test/unit-test/multi/test-continuable-erasure.cpp +++ b/test/unit-test/multi/test-continuable-erasure.cpp @@ -29,7 +29,13 @@ TYPED_TEST(single_dimension_tests, is_eraseable) { { cti::unique_continuable erasure = - cti::make_continuable(supplier_of(0xDF)); + cti::make_continuable(supplier_of(0xDF)); + + EXPECT_ASYNC_RESULT(std::move(erasure), 0xDF); + } + + { + cti::unique_continuable erasure = supplier_of(0xDF); EXPECT_ASYNC_RESULT(std::move(erasure), 0xDF); }