diff --git a/include/continuable/continuable-result.hpp b/include/continuable/continuable-result.hpp index b52f99c..e167359 100644 --- a/include/continuable/continuable-result.hpp +++ b/include/continuable/continuable-result.hpp @@ -86,15 +86,15 @@ public: /// A class similar to the one in the result proposal, /// however it's capable of carrying an exception_t. -// TODO -> async_result template class result { - using trait = detail::result_trait; - using value_t = typename trait::value_t; - - detail::container::flat_variant variant_; + using trait_t = detail::result_trait; + using surrogate_t = typename trait_t::surrogate_t; public: + using value_t = typename trait_t::value_t; + using exception_t = exception_t; + result() = default; result(result const&) = default; result(result&&) = default; @@ -103,9 +103,9 @@ public: ~result() = default; template ()...))* = nullptr> + decltype(trait_t::wrap(std::declval()...))* = nullptr> explicit result(Args&&... values) - : variant_(trait::wrap(std::forward(values)...)) { + : variant_(trait_t::wrap(std::forward(values)...)) { } explicit result(exception_t exception) : variant_(std::move(exception)) { } @@ -127,7 +127,7 @@ public: variant_.set_empty(); } void set_value(T... values) { - variant_ = trait::wrap(std::move(values)...); + variant_ = trait_t::wrap(std::move(values)...); } void set_exception(exception_t exception) { variant_ = std::move(exception); @@ -137,7 +137,7 @@ public: return variant_.is_empty(); } bool is_value() const noexcept { - return variant_.template is(); + return variant_.template is(); } bool is_exception() const noexcept { return variant_.template is(); @@ -147,15 +147,26 @@ public: return is_value(); } - value_t& get_value() & noexcept { - return variant_.template cast(); + decltype(auto) get_value() & noexcept { + return trait_t::unwrap(variant_.template cast()); } - value_t const& get_value() const& noexcept { - return variant_.template cast(); + decltype(auto) get_value() const& noexcept { + return trait_t::unwrap(variant_.template cast()); } - value_t&& get_value() && noexcept { - return std::move(variant_).template cast(); + decltype(auto) get_value() && noexcept { + return trait_t::unwrap(std::move(variant_).template cast()); } + + decltype(auto) operator*() & noexcept { + return get_value(); + } + decltype(auto) operator*() const& noexcept { + return get_value(); + } + decltype(auto) operator*() && noexcept { + return std::move(*this).get_value(); + } + exception_t& get_exception() & noexcept { return variant_.template cast(); } @@ -166,15 +177,8 @@ public: return std::move(variant_).template cast(); } - value_t& operator*() & noexcept { - return get_value(); - } - value_t const& operator*() const& noexcept { - return get_value(); - } - value_t&& operator*() && noexcept { - return std::move(*this).get_value(); - } +private: + detail::container::flat_variant variant_; }; template diff --git a/include/continuable/detail/core/base.hpp b/include/continuable/detail/core/base.hpp index 5d99a7f..d7a29e8 100644 --- a/include/continuable/detail/core/base.hpp +++ b/include/continuable/detail/core/base.hpp @@ -595,8 +595,8 @@ auto chain_continuation(Continuation&& continuation, Callback&& callback, return attorney::create_from( [continuation = std::forward(continuation), callback = std::forward(callback), - executor = - std::forward(executor)](auto&& next_callback) mutable { + executor = std::forward(executor)] // + (auto&& next_callback) mutable { // Invokes a continuation with a given callback. // Passes the next callback to the resulting continuable or // invokes the next callback directly if possible. diff --git a/include/continuable/detail/other/coroutines.hpp b/include/continuable/detail/other/coroutines.hpp index 2696263..2e22ad5 100644 --- a/include/continuable/detail/other/coroutines.hpp +++ b/include/continuable/detail/other/coroutines.hpp @@ -98,7 +98,7 @@ public: } /// Resume the coroutine represented by the handle - auto await_resume() noexcept(false) { + typename result_t::value_t await_resume() noexcept(false) { if (result_) { // When the result was resolved return it return std::move(result_).get_value(); @@ -120,8 +120,8 @@ private: } /// Resolve the continuation through an error - void resolve(exception_arg_t, exception_t error) { - result_.set_exception(std::move(error)); + void resolve(exception_arg_t, exception_t exception) { + result_.set_exception(std::move(exception)); } }; diff --git a/include/continuable/detail/utility/result-trait.hpp b/include/continuable/detail/utility/result-trait.hpp index a0429ce..cd18296 100644 --- a/include/continuable/detail/utility/result-trait.hpp +++ b/include/continuable/detail/utility/result-trait.hpp @@ -43,29 +43,44 @@ template struct result_trait; template <> struct result_trait<> { - struct value_t {}; + using value_t = void; + struct surrogate_t {}; - static constexpr value_t wrap() noexcept { + static constexpr surrogate_t wrap() noexcept { return {}; } + + static constexpr void unwrap(surrogate_t) { + } }; template struct result_trait { using value_t = T; + using surrogate_t = value_t; - static auto wrap(T arg) { + static surrogate_t wrap(T arg) { return std::move(arg); } + + template + static decltype(auto) unwrap(R&& unwrap) { + return std::forward(unwrap); + } }; template struct result_trait { using value_t = std::tuple; + using surrogate_t = value_t; - static std::tuple wrap(First first, Second second, - Rest... rest) { + static surrogate_t wrap(First first, Second second, Rest... rest) { return std::make_tuple(std::move(first), std::move(second), std::move(rest)...); } + + template + static decltype(auto) unwrap(R&& unwrap) { + return std::forward(unwrap); + } }; } // namespace detail } // namespace cti diff --git a/test/unit-test/multi/test-continuable-await.cpp b/test/unit-test/multi/test-continuable-await.cpp index 460ed49..90cc85e 100644 --- a/test/unit-test/multi/test-continuable-await.cpp +++ b/test/unit-test/multi/test-continuable-await.cpp @@ -39,7 +39,7 @@ cti::continuable<> resolve_async(S&& supplier) { co_await supplier(); // 1 args - int a1 = co_await supplier(1); + co_await supplier(1); EXPECT_EQ(a1, 1); // 2-n args @@ -66,7 +66,7 @@ cti::continuable resolve_async_multiple(S&& supplier) { } TYPED_TEST(single_dimension_tests, are_awaitable) { - auto const& supply = [&](auto&&... args) { + auto const supply = [&](auto&&... args) { // Supplies the current tested continuable return this->supply(std::forward(args)...); }; diff --git a/test/unit-test/single/test-continuable-result.cpp b/test/unit-test/single/test-continuable-result.cpp index 426e1ed..0168a10 100644 --- a/test/unit-test/single/test-continuable-result.cpp +++ b/test/unit-test/single/test-continuable-result.cpp @@ -28,8 +28,8 @@ #include using cti::exception_t; -using cti::result; using cti::make_result; +using cti::result; static int const CANARY = 373671; @@ -66,10 +66,17 @@ TYPED_TEST_CASE(result_all_tests, result_test_types); TYPED_TEST(result_all_tests, is_default_constructible) { TypeParam e; result<> e1; + static_assert(std::is_void::value); + EXPECT_TRUE(e1.is_empty()); + result e2; + EXPECT_TRUE(e2.is_empty()); + result e3; + EXPECT_TRUE(e3.is_empty()); auto empty = make_result(); + EXPECT_TRUE(empty.is_empty()); } TYPED_TEST(result_all_tests, can_carry_errors) {