diff --git a/include/continuable/detail/expected.hpp b/include/continuable/detail/expected.hpp index dbd70d3..7fb455e 100644 --- a/include/continuable/detail/expected.hpp +++ b/include/continuable/detail/expected.hpp @@ -36,12 +36,31 @@ #include #include +#include namespace cti { namespace detail { namespace expected { -/// A tag which is passed to the visitor when the expected type is empty -struct empty_guard_tag {}; +namespace detail { +template +struct expected_base { + explicit expected_base(expected_base const& right) { + static_cast(&right)->visit([&](auto&& value) { + using type = std::decay_t; + auto storage = &static_cast(this)->storage_; + new (storage) type(std::forward(value)); + }); + } + expected_base& operator=(expected_base const& right) { + static_cast(&right)->visit([&](auto&& value) { + using type = std::decay_t; + auto storage = &static_cast(this)->storage_; + new (storage) type(std::forward(value)); + }); + return *this; + } +}; +} // namespace detail /// A class similar to the one in the expected proposal, /// however it is capable of carrying an exception_ptr if @@ -49,6 +68,8 @@ struct empty_guard_tag {}; template > class expected { + friend class expected_base; + enum class slot_t { empty, value, error }; Storage storage_; @@ -74,14 +95,29 @@ public: return slot_ == slot_t::error; } - template - auto visit(T&& visitor) - -> decltype(std::forward(visitor)(empty_guard_tag{})) { - - switch(slot_) - { - + template + void visit(V&& visitor) { + switch (slot_) { + case slot_t::value: + return std::forward(visitor)(static_cast(&storage_)); + case slot_t::error: + return std::forward(visitor)( + static_cast(&storage_)); } + + util::unreachable(); + } + template + void visit(V&& visitor) const { + switch (slot_) { + case slot_t::value: + return std::forward(visitor)(static_cast(&storage_)); + case slot_t::error: + return std::forward(visitor)( + static_cast(&storage_)); + } + + util::unreachable(); } }; } // namespace expected