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,
/// however it's capable of carrying an exception_t.
// TODO -> async_result
template <typename... T>
class result {
using trait = detail::result_trait<T...>;
using value_t = typename trait::value_t;
detail::container::flat_variant<value_t, exception_t> variant_;
using trait_t = detail::result_trait<T...>;
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 <typename... Args,
decltype(trait::wrap(std::declval<Args>()...))* = nullptr>
decltype(trait_t::wrap(std::declval<Args>()...))* = nullptr>
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)) {
}
@ -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<value_t>();
return variant_.template is<surrogate_t>();
}
bool is_exception() const noexcept {
return variant_.template is<exception_t>();
@ -147,15 +147,26 @@ public:
return is_value();
}
value_t& get_value() & noexcept {
return variant_.template cast<value_t>();
decltype(auto) get_value() & noexcept {
return trait_t::unwrap(variant_.template cast<surrogate_t>());
}
value_t const& get_value() const& noexcept {
return variant_.template cast<value_t>();
decltype(auto) get_value() const& noexcept {
return trait_t::unwrap(variant_.template cast<surrogate_t>());
}
value_t&& get_value() && noexcept {
return std::move(variant_).template cast<value_t>();
decltype(auto) get_value() && noexcept {
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 {
return variant_.template cast<exception_t>();
}
@ -166,15 +177,8 @@ public:
return std::move(variant_).template cast<exception_t>();
}
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<surrogate_t, exception_t> variant_;
};
template <typename T>

View File

@ -595,8 +595,8 @@ auto chain_continuation(Continuation&& continuation, Callback&& callback,
return attorney::create_from(
[continuation = std::forward<Continuation>(continuation),
callback = std::forward<Callback>(callback),
executor =
std::forward<Executor>(executor)](auto&& next_callback) mutable {
executor = std::forward<Executor>(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.

View File

@ -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));
}
};

View File

@ -43,29 +43,44 @@ template <typename... T>
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 <typename T>
struct result_trait<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);
}
template <typename R>
static decltype(auto) unwrap(R&& unwrap) {
return std::forward<R>(unwrap);
}
};
template <typename First, typename Second, typename... Rest>
struct result_trait<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,
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 <typename R>
static decltype(auto) unwrap(R&& unwrap) {
return std::forward<R>(unwrap);
}
};
} // namespace detail
} // namespace cti

View File

@ -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<int, int, int, int> 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<decltype(args)>(args)...);
};

View File

@ -28,8 +28,8 @@
#include <test-continuable.hpp>
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<decltype(e1.get_value())>::value);
EXPECT_TRUE(e1.is_empty());
result<int> e2;
EXPECT_TRUE(e2.is_empty());
result<int, int> e3;
EXPECT_TRUE(e3.is_empty());
auto empty = make_result();
EXPECT_TRUE(empty.is_empty());
}
TYPED_TEST(result_all_tests, can_carry_errors) {