Make result<> return void when calling get_value()

This commit is contained in:
Denis Blank 2018-11-25 19:56:03 +01:00
parent 5354d3512e
commit cd367b3d43
6 changed files with 63 additions and 37 deletions

View File

@ -86,15 +86,15 @@ public:
/// A class similar to the one in the result proposal, /// A class similar to the one in the result proposal,
/// however it's capable of carrying an exception_t. /// however it's capable of carrying an exception_t.
// TODO -> async_result
template <typename... T> template <typename... T>
class result { class result {
using trait = detail::result_trait<T...>; using trait_t = detail::result_trait<T...>;
using value_t = typename trait::value_t; using surrogate_t = typename trait_t::surrogate_t;
detail::container::flat_variant<value_t, exception_t> variant_;
public: public:
using value_t = typename trait_t::value_t;
using exception_t = exception_t;
result() = default; result() = default;
result(result const&) = default; result(result const&) = default;
result(result&&) = default; result(result&&) = default;
@ -103,9 +103,9 @@ public:
~result() = default; ~result() = default;
template <typename... Args, template <typename... Args,
decltype(trait::wrap(std::declval<Args>()...))* = nullptr> decltype(trait_t::wrap(std::declval<Args>()...))* = nullptr>
explicit result(Args&&... values) explicit result(Args&&... values)
: variant_(trait::wrap(std::forward<Args>(values)...)) { : variant_(trait_t::wrap(std::forward<Args>(values)...)) {
} }
explicit result(exception_t exception) : variant_(std::move(exception)) { explicit result(exception_t exception) : variant_(std::move(exception)) {
} }
@ -127,7 +127,7 @@ public:
variant_.set_empty(); variant_.set_empty();
} }
void set_value(T... values) { void set_value(T... values) {
variant_ = trait::wrap(std::move(values)...); variant_ = trait_t::wrap(std::move(values)...);
} }
void set_exception(exception_t exception) { void set_exception(exception_t exception) {
variant_ = std::move(exception); variant_ = std::move(exception);
@ -137,7 +137,7 @@ public:
return variant_.is_empty(); return variant_.is_empty();
} }
bool is_value() const noexcept { bool is_value() const noexcept {
return variant_.template is<value_t>(); return variant_.template is<surrogate_t>();
} }
bool is_exception() const noexcept { bool is_exception() const noexcept {
return variant_.template is<exception_t>(); return variant_.template is<exception_t>();
@ -147,15 +147,26 @@ public:
return is_value(); return is_value();
} }
value_t& get_value() & noexcept { decltype(auto) get_value() & noexcept {
return variant_.template cast<value_t>(); return trait_t::unwrap(variant_.template cast<surrogate_t>());
} }
value_t const& get_value() const& noexcept { decltype(auto) get_value() const& noexcept {
return variant_.template cast<value_t>(); return trait_t::unwrap(variant_.template cast<surrogate_t>());
} }
value_t&& get_value() && noexcept { decltype(auto) get_value() && noexcept {
return std::move(variant_).template cast<value_t>(); return trait_t::unwrap(std::move(variant_).template cast<surrogate_t>());
} }
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 { exception_t& get_exception() & noexcept {
return variant_.template cast<exception_t>(); return variant_.template cast<exception_t>();
} }
@ -166,15 +177,8 @@ public:
return std::move(variant_).template cast<exception_t>(); return std::move(variant_).template cast<exception_t>();
} }
value_t& operator*() & noexcept { private:
return get_value(); detail::container::flat_variant<surrogate_t, exception_t> variant_;
}
value_t const& operator*() const& noexcept {
return get_value();
}
value_t&& operator*() && noexcept {
return std::move(*this).get_value();
}
}; };
template <typename T> template <typename T>

View File

@ -595,8 +595,8 @@ auto chain_continuation(Continuation&& continuation, Callback&& callback,
return attorney::create_from( return attorney::create_from(
[continuation = std::forward<Continuation>(continuation), [continuation = std::forward<Continuation>(continuation),
callback = std::forward<Callback>(callback), callback = std::forward<Callback>(callback),
executor = executor = std::forward<Executor>(executor)] //
std::forward<Executor>(executor)](auto&& next_callback) mutable { (auto&& next_callback) mutable {
// Invokes a continuation with a given callback. // Invokes a continuation with a given callback.
// Passes the next callback to the resulting continuable or // Passes the next callback to the resulting continuable or
// invokes the next callback directly if possible. // invokes the next callback directly if possible.

View File

@ -98,7 +98,7 @@ public:
} }
/// Resume the coroutine represented by the handle /// Resume the coroutine represented by the handle
auto await_resume() noexcept(false) { typename result_t::value_t await_resume() noexcept(false) {
if (result_) { if (result_) {
// When the result was resolved return it // When the result was resolved return it
return std::move(result_).get_value(); return std::move(result_).get_value();
@ -120,8 +120,8 @@ private:
} }
/// Resolve the continuation through an error /// Resolve the continuation through an error
void resolve(exception_arg_t, exception_t error) { void resolve(exception_arg_t, exception_t exception) {
result_.set_exception(std::move(error)); result_.set_exception(std::move(exception));
} }
}; };

View File

@ -43,29 +43,44 @@ template <typename... T>
struct result_trait; struct result_trait;
template <> template <>
struct result_trait<> { 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 {}; return {};
} }
static constexpr void unwrap(surrogate_t) {
}
}; };
template <typename T> template <typename T>
struct result_trait<T> { struct result_trait<T> {
using value_t = T; using value_t = T;
using surrogate_t = value_t;
static auto wrap(T arg) { static surrogate_t wrap(T arg) {
return std::move(arg); return std::move(arg);
} }
template <typename R>
static decltype(auto) unwrap(R&& unwrap) {
return std::forward<R>(unwrap);
}
}; };
template <typename First, typename Second, typename... Rest> template <typename First, typename Second, typename... Rest>
struct result_trait<First, Second, Rest...> { struct result_trait<First, Second, Rest...> {
using value_t = std::tuple<First, Second, Rest...>; using value_t = std::tuple<First, Second, Rest...>;
using surrogate_t = value_t;
static std::tuple<First, Second, Rest...> wrap(First first, Second second, static surrogate_t wrap(First first, Second second, Rest... rest) {
Rest... rest) {
return std::make_tuple(std::move(first), std::move(second), return std::make_tuple(std::move(first), std::move(second),
std::move(rest)...); std::move(rest)...);
} }
template <typename R>
static decltype(auto) unwrap(R&& unwrap) {
return std::forward<R>(unwrap);
}
}; };
} // namespace detail } // namespace detail
} // namespace cti } // namespace cti

View File

@ -39,7 +39,7 @@ cti::continuable<> resolve_async(S&& supplier) {
co_await supplier(); co_await supplier();
// 1 args // 1 args
int a1 = co_await supplier(1); co_await supplier(1);
EXPECT_EQ(a1, 1); EXPECT_EQ(a1, 1);
// 2-n args // 2-n args
@ -66,7 +66,7 @@ cti::continuable<int, int, int, int> resolve_async_multiple(S&& supplier) {
} }
TYPED_TEST(single_dimension_tests, are_awaitable) { TYPED_TEST(single_dimension_tests, are_awaitable) {
auto const& supply = [&](auto&&... args) { auto const supply = [&](auto&&... args) {
// Supplies the current tested continuable // Supplies the current tested continuable
return this->supply(std::forward<decltype(args)>(args)...); return this->supply(std::forward<decltype(args)>(args)...);
}; };

View File

@ -28,8 +28,8 @@
#include <test-continuable.hpp> #include <test-continuable.hpp>
using cti::exception_t; using cti::exception_t;
using cti::result;
using cti::make_result; using cti::make_result;
using cti::result;
static int const CANARY = 373671; 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) { TYPED_TEST(result_all_tests, is_default_constructible) {
TypeParam e; TypeParam e;
result<> e1; result<> e1;
static_assert(std::is_void<decltype(e1.get_value())>::value);
EXPECT_TRUE(e1.is_empty());
result<int> e2; result<int> e2;
EXPECT_TRUE(e2.is_empty());
result<int, int> e3; result<int, int> e3;
EXPECT_TRUE(e3.is_empty());
auto empty = make_result(); auto empty = make_result();
EXPECT_TRUE(empty.is_empty());
} }
TYPED_TEST(result_all_tests, can_carry_errors) { TYPED_TEST(result_all_tests, can_carry_errors) {