diff --git a/expected.hpp b/expected.hpp index 5108ee7..41ab1a7 100644 --- a/expected.hpp +++ b/expected.hpp @@ -163,6 +163,11 @@ constexpr bool operator>=(const unexpected &lhs, const unexpected &rhs) { return lhs.value() >= rhs.value(); } +template +unexpected make_unexpected (E&& e) { + return unexpected(std::forward(e)); +} + struct unexpect_t { unexpect_t() = default; }; @@ -393,7 +398,7 @@ template struct expected_storage_base { }; // TODO, conditionally delete things -template class expected_ctor_base {}; + template struct expected_ctor_base {}; } // namespace detail template class bad_expected_access : public std::exception { @@ -414,8 +419,7 @@ private: }; template -class expected : private detail::expected_storage_base, - private detail::expected_ctor_base { +class expected : private detail::expected_storage_base { static_assert(!std::is_reference::value, "T must not be a reference"); static_assert(!std::is_same>::value, "T must not be in_place_t"); @@ -696,14 +700,14 @@ public: detail::enable_if_t::value> * = nullptr> explicit constexpr expected(unexpected const &e) - : storage_base(unexpect, e) {} + : storage_base(unexpect, e.value()) {} template < class G = E, detail::enable_if_t::value> * = nullptr, detail::enable_if_t::value> * = nullptr> - constexpr expected(unexpected const &e) : storage_base(unexpect, e) {} + constexpr expected(unexpected const &e) : storage_base(unexpect, e.value()) {} template < class G = E, @@ -711,7 +715,7 @@ public: detail::enable_if_t::value> * = nullptr> explicit constexpr expected(unexpected &&e) noexcept( std::is_nothrow_constructible::value) - : storage_base(unexpect, std::move(e)) {} + : storage_base(unexpect, std::move(e.value())) {} template < class G = E, @@ -719,7 +723,7 @@ public: detail::enable_if_t::value> * = nullptr> constexpr expected(unexpected &&e) noexcept( std::is_nothrow_constructible::value) - : storage_base(unexpect, std::move(e)) {} + : storage_base(unexpect, std::move(e.value())) {} template ::value> * = @@ -803,80 +807,13 @@ public: constexpr expected(U &&v) : expected(in_place, std::forward(v)) {} // TODO conditionally delete - template ::value>* = nullptr> - expected &operator=(const expected &rhs) noexcept { - if (!has_value() && rhs.has_value()) { - err().~unexpected(); - ::new (valptr()) T (*rhs); - this->m_has_value = true; - return *this; - } - + expected& operator=(const expected& rhs) { return assign(rhs); } - template ::value && std::is_nothrow_move_constructible::value>* = nullptr> - expected &operator=(const expected &rhs) noexcept { - if (!has_value() && rhs.has_value()) { - T tmp = *rhs; - err().~unexpected(); - ::new (valptr()) T (std::move(tmp)); - this->m_has_value = true; - return *this; - } - - return assign(rhs); + expected& operator=(expected&& rhs) { + return assign(std::move(rhs)); } - - template ::value && !std::is_nothrow_move_constructible::value>* = nullptr> - expected &operator=(const expected &rhs) { - if (!has_value() && rhs.has_value()) { - auto tmp = std::move(err()); - err().~unexpected(); - - try { - ::new (valptr()) T (*rhs); - this->m_has_value = true; - } - catch(...) { - err() = std::move(tmp); - throw; - } - this->m_has_value = true; - return *this; - } - - return assign(rhs); - } - - template ::value>* = nullptr> - expected &operator=(expected && rhs) noexcept { - if (!has_value() && rhs.has_value()) { - err().~unexpected(); - ::new (valptr()) T (*std::move(rhs)); - } - - return assign(rhs); - } - - template ::value>* = nullptr> - expected &operator=(expected && rhs) { - if (!has_value() && rhs.has_value()) { - auto tmp = std::move(err()); - err().~unexpected(); - try { - ::new (valptr()) T (*std::move(rhs)); - this->m_has_value = true; - } - catch (...) { - err() = std::move(tmp); - throw; - } - } - - return assign(rhs); - } - template , detail::decay_t>::value && @@ -891,7 +828,7 @@ public: else { err().~unexpected(); ::new (valptr()) T (std::forward(v)); - this->m_has_value = true; + this->m_has_val = true; } return *this; @@ -914,7 +851,7 @@ public: err().~unexpected(); try { ::new (valptr()) T (std::move(v)); - this->m_has_value = true; + this->m_has_val = true; } catch (...) { err() = std::move(tmp); @@ -965,7 +902,7 @@ public: else { err().~unexpected(); ::new (valptr()) T (std::forward(args)...); - this->m_has_value = true; + this->m_has_val = true; } } @@ -981,7 +918,7 @@ public: try { ::new (valptr()) T (std::forward(args)...); - this->m_has_value = true; + this->m_has_val = true; } catch (...) { err() = std::move(tmp); @@ -1000,7 +937,7 @@ public: else { err().~unexpected(); ::new (valptr()) T (il, std::forward(args)...); - this->m_has_value = true; + this->m_has_val = true; } } @@ -1017,7 +954,7 @@ public: try { ::new (valptr()) T (il, std::forward(args)...); - this->m_has_value = true; + this->m_has_val = true; } catch (...) { err() = std::move(tmp); @@ -1098,8 +1035,87 @@ public: private: + template ::value>* = nullptr> + expected &assign(const expected &rhs) noexcept { + if (!has_value() && rhs.has_value()) { + err().~unexpected(); + ::new (valptr()) T (*rhs); + this->m_has_val = true; + return *this; + } + + return assign_common(rhs); + } + + template ::value && std::is_nothrow_move_constructible::value>* = nullptr> + expected &assign(const expected &rhs) noexcept { + if (!has_value() && rhs.has_value()) { + T tmp = *rhs; + err().~unexpected(); + ::new (valptr()) T (std::move(tmp)); + this->m_has_val = true; + return *this; + } + + return assign_common(rhs); + } + + template ::value && !std::is_nothrow_move_constructible::value>* = nullptr> + expected &assign(const expected &rhs) { + if (!has_value() && rhs.has_value()) { + auto tmp = std::move(err()); + err().~unexpected(); + + try { + ::new (valptr()) T (*rhs); + this->m_has_val = true; + } + catch(...) { + err() = std::move(tmp); + throw; + } + this->m_has_val = true; + return *this; + } + + return assign_common(rhs); + } + + template ::value>* = nullptr> + expected &assign(expected && rhs) noexcept { + if (!has_value() && rhs.has_value()) { + err().~unexpected(); + ::new (valptr()) T (*std::move(rhs)); + this->m_has_val = true; + return *this; + } + + return assign_common(rhs); + } + + template ::value>* = nullptr> + expected &assign(expected && rhs) { + if (!has_value() && rhs.has_value()) { + auto tmp = std::move(err()); + err().~unexpected(); + try { + ::new (valptr()) T (*std::move(rhs)); + this->m_has_val = true; + } + catch (...) { + err() = std::move(tmp); + throw; + } + + return *this; + } + + return assign_common(rhs); + } + + template - expected& assign(Rhs&& rhs) { + expected& assign_common(Rhs&& rhs) { if (has_value()) { if (rhs.has_value()) { val() = *std::forward(rhs);