diff --git a/optional.hpp b/optional.hpp index c5dcb3a..54bf141 100644 --- a/optional.hpp +++ b/optional.hpp @@ -55,20 +55,20 @@ namespace tl { }; static constexpr in_place_t in_place{}; - // [optional.optional], class template optional - template - class optional; + // [optional.optional], class template optional + template + class optional; namespace detail { template - using enable_forward_value = tl::enable_if_t< + using enable_forward_value = enable_if_t< std::is_constructible::value && !std::is_same, in_place_t>::value && !std::is_same, tl::decay_t>::value - >; + >; template - using enable_from_other = tl::enable_if_t< + using enable_from_other = enable_if_t< std::is_constructible::value && !std::is_constructible&>::value && !std::is_constructible&&>::value && @@ -78,58 +78,59 @@ namespace tl { !std::is_convertible&&, T>::value && !std::is_convertible&, T>::value && !std::is_convertible&&, T>::value - >; + >; template - using enable_assign_forward = tl::enable_if_t< - !is_same_v, tl::decay_t>::value && + using enable_assign_forward = enable_if_t< + !std::is_same, tl::decay_t>::value && !tl::conjunction, std::is_same>>::value && std::is_constructible::value && - is_assignable::value - >; + std::is_assignable::value + >; template - using enable_assign_from_other = tl::enable_if_t< - std::is_constructible && - std::is_assignablev && - !std::is_constructiblev&> && - !std::is_constructiblev&&> && - !std::is_constructiblev&> && - !std::is_constructiblev&&> && - !std::is_convertiblev&, T> && - !std::is_convertiblev&&, T> && - !std::is_convertiblev&, T> && - !std::is_convertiblev&&, T> && - !std::is_assignablev&> && - !std::is_assignablev&&> && - !std::is_assignablev&> && - !std::is_assignablev&&> - > + using enable_assign_from_other = enable_if_t< + std::is_constructible::value && + std::is_assignable::value && + !std::is_constructible&>::value && + !std::is_constructible&&>::value && + !std::is_constructible&>::value && + !std::is_constructible&&>::value && + !std::is_convertible&, T>::value && + !std::is_convertible&&, T>::value && + !std::is_convertible&, T>::value && + !std::is_convertible&&, T>::value && + !std::is_assignable&>::value && + !std::is_assignable&&>::value && + !std::is_assignable&>::value && + !std::is_assignable&&>::value + >; - //TODO improve - template - struct is_swappable : std::false_type{}; + //TODO improve + template + struct is_swappable : std::false_type{}; - template - struct is_swappable(), std::declval()))>> - : std::true_type{}; + template + struct is_swappable(), std::declval()))>> + : std::true_type{}; - //TODO improve - template - struct is_nothrow_swappable : std::false_type{}; + //TODO improve + template + struct is_nothrow_swappable : std::false_type{}; - template - struct is_nothrow_swappable(), std::declval()))>> - : std::true_type{}; + template + struct is_nothrow_swappable(), std::declval()))>> + : std::true_type{}; + } - // [optional.nullopt], no-value state indicator - struct nullopt_t{ - struct do_not_use{}; - constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept{} - }; + // [optional.nullopt], no-value state indicator + struct nullopt_t{ + struct do_not_use{}; + constexpr explicit nullopt_t(do_not_use, do_not_use) noexcept{} + }; static constexpr nullopt_t nullopt{nullopt_t::do_not_use{}, nullopt_t::do_not_use{}}; - // [optional.bad.access], class bad_optional_access + // [optional.bad.access], class bad_optional_access class bad_optional_access : public std::exception { public: bad_optional_access() = default; @@ -138,158 +139,158 @@ namespace tl { } }; - // [optional.relops], relational operators - template - inline constexpr bool operator==(const optional& lhs, const optional& rhs) { - if (lhs.has_value() != rhs.has_value()) - return false; - if (lhs.has_value()) - return true; + // [optional.relops], relational operators + template + inline constexpr bool operator==(const optional& lhs, const optional& rhs) { + if (lhs.has_value() != rhs.has_value()) + return false; + if (lhs.has_value()) + return true; - return lhs.value() == rhs.value(); - } - template - inline constexpr bool operator!=(const optional& lhs, const optional& rhs) { - if (lhs.has_value() != rhs.has_value()) - return true; - if (lhs.has_value()) - return false; + return lhs.value() == rhs.value(); + } + template + inline constexpr bool operator!=(const optional& lhs, const optional& rhs) { + if (lhs.has_value() != rhs.has_value()) + return true; + if (lhs.has_value()) + return false; - return lhs.value() != rhs.value(); - } - template - inline constexpr bool operator<(const optional& lhs, const optional& rhs) { - if (!rhs.has_value()) - return false; - if (!lhs.has_value()) - return true; + return lhs.value() != rhs.value(); + } + template + inline constexpr bool operator<(const optional& lhs, const optional& rhs) { + if (!rhs.has_value()) + return false; + if (!lhs.has_value()) + return true; - return lhs.value() < rhs.value(); - } - template - inline constexpr bool operator>(const optional& lhs, const optional& rhs) { - if (!lhs.has_value()) - return false; - if (!rhs.has_value()) - return true; + return lhs.value() < rhs.value(); + } + template + inline constexpr bool operator>(const optional& lhs, const optional& rhs) { + if (!lhs.has_value()) + return false; + if (!rhs.has_value()) + return true; - return lhs.value() > rhs.value(); - } - template - inline constexpr bool operator<=(const optional& lhs, const optional& rhs) { - if (!lhs.has_value()) - return true; - if (!rhs.has_value()) - return false; + return lhs.value() > rhs.value(); + } + template + inline constexpr bool operator<=(const optional& lhs, const optional& rhs) { + if (!lhs.has_value()) + return true; + if (!rhs.has_value()) + return false; - return lhs.value() <= rhs.value(); - } - template - inline constexpr bool operator>=(const optional& lhs, const optional& rhs) { - if (!rhs.has_value()) - return true; - if (!lhs.has_value()) - return false; + return lhs.value() <= rhs.value(); + } + template + inline constexpr bool operator>=(const optional& lhs, const optional& rhs) { + if (!rhs.has_value()) + return true; + if (!lhs.has_value()) + return false; - return lhs.value() >= rhs.value(); - } + return lhs.value() >= rhs.value(); + } - // [optional.nullops], comparison with nullopt -template inline constexpr bool operator==(const optional& lhs, nullopt_t) noexcept { - return !lhs.has_value(); -} -template inline constexpr bool operator==(nullopt_t, const optional& rhs) noexcept { - return !rhs.has_value(); -} -template inline constexpr bool operator!=(const optional& lhs, nullopt_t) noexcept { - return lhs.has_value(); -} -template inline constexpr bool operator!=(nullopt_t, const optional& rhs) noexcept { - return rhs.has_value(); -} -template inline constexpr bool operator<(const optional&, nullopt_t) noexcept { - return false; -} -template inline constexpr bool operator<(nullopt_t, const optional& rhs) noexcept { - return rhs.has_value(); -} -template inline constexpr bool operator<=(const optional& lhs, nullopt_t) noexcept { - return !lhs.has_value(); -} -template inline constexpr bool operator<=(nullopt_t, const optional&) noexcept { - return true; -} -template inline constexpr bool operator>(const optional& lhs, nullopt_t) noexcept { - return lhs.has_value(); -} -template inline constexpr bool operator>(nullopt_t, const optional&) noexcept { - return false; -} -template inline constexpr bool operator>=(const optional&, nullopt_t) noexcept { - return true; -} -template inline constexpr bool operator>=(nullopt_t, const optional& rhs) noexcept { - return !rhs.has_value(); -} + // [optional.nullops], comparison with nullopt + template inline constexpr bool operator==(const optional& lhs, nullopt_t) noexcept { + return !lhs.has_value(); + } + template inline constexpr bool operator==(nullopt_t, const optional& rhs) noexcept { + return !rhs.has_value(); + } + template inline constexpr bool operator!=(const optional& lhs, nullopt_t) noexcept { + return lhs.has_value(); + } + template inline constexpr bool operator!=(nullopt_t, const optional& rhs) noexcept { + return rhs.has_value(); + } + template inline constexpr bool operator<(const optional&, nullopt_t) noexcept { + return false; + } + template inline constexpr bool operator<(nullopt_t, const optional& rhs) noexcept { + return rhs.has_value(); + } + template inline constexpr bool operator<=(const optional& lhs, nullopt_t) noexcept { + return !lhs.has_value(); + } + template inline constexpr bool operator<=(nullopt_t, const optional&) noexcept { + return true; + } + template inline constexpr bool operator>(const optional& lhs, nullopt_t) noexcept { + return lhs.has_value(); + } + template inline constexpr bool operator>(nullopt_t, const optional&) noexcept { + return false; + } + template inline constexpr bool operator>=(const optional&, nullopt_t) noexcept { + return true; + } + template inline constexpr bool operator>=(nullopt_t, const optional& rhs) noexcept { + return !rhs.has_value(); + } - // [optional.comp_with_t], comparison with T -template inline constexpr bool operator==(const optional& lhs, const U& rhs) { - return lhs.has_value() ? *lhs == rhs : false; -} -template inline constexpr bool operator==(const U& lhs, const optional& rhs) { - return rhs.has_value() ? lhs == rhs.value() : false; -} -template inline constexpr bool operator!=(const optional& lhs, const U& rhs) { - return lhs.has_value() ? lhs.value() != lhs : true; -} -template inline constexpr bool operator!=(const U& lhs, const optional& rhs) { - return rhs.has_value() ? lhs != rhs.value() : true; -} -template inline constexpr bool operator<(const optional& lhs, const U& rhs) { - return lhs.has_value() ? lhs.value() < lhs : true; -} -template inline constexpr bool operator<(const U& lhs, const optional& rhs) { - return rhs.has_value() ? lhs < rhs.value() : false; -} -template inline constexpr bool operator<=(const optional& lhs, const U& rhs) { - return lhs.has_value() ? lhs.value() <= lhs : true; -} -template inline constexpr bool operator<=(const U& lhs, const optional& rhs) { - return rhs.has_value() ? lhs <= rhs.value() : false; -} -template inline constexpr bool operator>(const optional& lhs, const U& rhs) { - return lhs.has_value() ? lhs.value() > lhs : false; -} -template inline constexpr bool operator>(const U& lhs, const optional& rhs) { - return rhs.has_value() ? lhs > rhs.value() : true; -} -template inline constexpr bool operator>=(const optional& lhs, const U& rhs) { - return lhs.has_value() ? lhs.value() >= lhs : false; -} -template inline constexpr bool operator>=(const U& lhs, const optional& rhs) { - return rhs.has_value() ? lhs >= rhs.value() : true; -} + // [optional.comp_with_t], comparison with T + template inline constexpr bool operator==(const optional& lhs, const U& rhs) { + return lhs.has_value() ? *lhs == rhs : false; + } + template inline constexpr bool operator==(const U& lhs, const optional& rhs) { + return rhs.has_value() ? lhs == rhs.value() : false; + } + template inline constexpr bool operator!=(const optional& lhs, const U& rhs) { + return lhs.has_value() ? lhs.value() != lhs : true; + } + template inline constexpr bool operator!=(const U& lhs, const optional& rhs) { + return rhs.has_value() ? lhs != rhs.value() : true; + } + template inline constexpr bool operator<(const optional& lhs, const U& rhs) { + return lhs.has_value() ? lhs.value() < lhs : true; + } + template inline constexpr bool operator<(const U& lhs, const optional& rhs) { + return rhs.has_value() ? lhs < rhs.value() : false; + } + template inline constexpr bool operator<=(const optional& lhs, const U& rhs) { + return lhs.has_value() ? lhs.value() <= lhs : true; + } + template inline constexpr bool operator<=(const U& lhs, const optional& rhs) { + return rhs.has_value() ? lhs <= rhs.value() : false; + } + template inline constexpr bool operator>(const optional& lhs, const U& rhs) { + return lhs.has_value() ? lhs.value() > lhs : false; + } + template inline constexpr bool operator>(const U& lhs, const optional& rhs) { + return rhs.has_value() ? lhs > rhs.value() : true; + } + template inline constexpr bool operator>=(const optional& lhs, const U& rhs) { + return lhs.has_value() ? lhs.value() >= lhs : false; + } + template inline constexpr bool operator>=(const U& lhs, const optional& rhs) { + return rhs.has_value() ? lhs >= rhs.value() : true; + } - // [optional.specalg], specialized algorithms -template ::value>* = nullptr, - tl::enable_if_t::value>* = nullptr> -void swap(optional& lhs, optional& rhs) noexcept(noexcept(lhs.swap(rhs))) { - return lhs.swap(rhs); -} + // [optional.specalg], specialized algorithms + template ::value>* = nullptr, + enable_if_t::value>* = nullptr> + void swap(optional& lhs, optional& rhs) noexcept(noexcept(lhs.swap(rhs))) { + return lhs.swap(rhs); + } - template - inline constexpr optional> make_optional(T&& v) { - return optional>(std::forward(v)); - } - template - inline constexpr optional make_optional(Args&&... args) { - return optional(in_place, std::forward(args)...); - } - template - inline constexpr optional make_optional(std::initializer_list il, Args&&... args) { - return optional(in_place, il, std::forward(args)...); - } + template + inline constexpr optional> make_optional(T&& v) { + return optional>(std::forward(v)); + } + template + inline constexpr optional make_optional(Args&&... args) { + return optional(in_place, std::forward(args)...); + } + template + inline constexpr optional make_optional(std::initializer_list il, Args&&... args) { + return optional(in_place, il, std::forward(args)...); + } } // [optional.hash], hash support @@ -297,7 +298,7 @@ namespace std { //TODO SFINAE template struct hash> { - std::size_t operator() (const tl::optional& o) const { + ::std::size_t operator() (const tl::optional& o) const { if (!o.has_value()) return 0; @@ -307,9 +308,8 @@ namespace std { } namespace tl { - namespace detail { - template ::value> + template ::value> struct optional_storage_base { constexpr optional_storage_base() noexcept : m_dummy(), m_has_value(false) {} @@ -333,12 +333,7 @@ namespace tl { struct optional_storage_base { constexpr optional_storage_base() noexcept : m_dummy(), m_has_value(false) {} - ~optional_storage_base() { - if (m_has_value) { - //don't destruct value - m_has_value = false; - } - } + ~optional_storage_base() = default; struct dummy{}; union { @@ -350,273 +345,273 @@ namespace tl { }; } -template -class optional : private detail::optional_storage_base { - public: - using value_type = T; + template + class optional : private detail::optional_storage_base { + public: + using value_type = T; - // [optional.ctor], constructors - constexpr optional() noexcept = default; - constexpr optional(nullopt_t) noexcept {}; - constexpr optional(const optional& rhs) { - if (rhs.has_value()) { + // [optional.ctor], constructors + constexpr optional() noexcept = default; + constexpr optional(nullopt_t) noexcept {}; + constexpr optional(const optional& rhs) { + if (rhs.has_value()) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (rhs.value()); + } + } + template ::value>* = nullptr> + constexpr optional(optional&& rhs) { + if (rhs.has_value()) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::move(rhs.value())); + } + } + template + constexpr explicit optional(enable_if_t::value, in_place_t>, + Args&&... args) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::forward(args)...); + } + template + constexpr explicit optional( + enable_if_t&, Args&&...>::value, in_place_t>, + std::initializer_list il, Args&&... args) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (il, std::forward(args)...); + } + + template ::value>* = nullptr, + detail::enable_forward_value* = nullptr> + constexpr optional(U&& u) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::forward(u)); + } + + template ::value>* = nullptr, + detail::enable_forward_value* = nullptr> + constexpr explicit optional(U&& u) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::forward(u)); + } + + template * = nullptr, + enable_if_t::value>* = nullptr> + optional(const optional& rhs) { this->m_has_value = true; new (std::addressof(this->m_value)) T (rhs.value()); } - } - template ::value>* = nullptr> - constexpr optional(optional&& rhs) { + + template * = nullptr, + enable_if_t::value>* = nullptr> + optional(const optional& rhs) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (rhs.value()); + } + + template * = nullptr, + enable_if_t::value>* = nullptr> + optional(optional&& rhs) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::move(rhs.value())); + } + + + template * = nullptr, + enable_if_t::value>* = nullptr> + explicit optional(optional&& rhs) { + this->m_has_value = true; + new (std::addressof(this->m_value)) T (std::move(rhs.value())); + } + + // [optional.dtor], destructor + ~optional() = default; + + // [optional.assign], assignment + optional& operator=(nullopt_t) noexcept { + if (has_value()) { + this->m_value.~T(); + this->m_has_value = false; + } + } + + // TODO conditionally delete, check exception guarantee + optional& operator=(const optional& rhs) { + if (has_value()) { if (rhs.has_value()) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (std::move(rhs.value())); + this->m_value = rhs.m_value; + } + else { + this->m_value.~T(); + this->m_has_value = false; } } - template - constexpr explicit optional(tl::enable_if_t::value, in_place_t>, - Args&&... args) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (std::forward(args)...); - } - template - constexpr explicit optional( - tl::enable_if_t&, Args&&...>::value, in_place_t>, - std::initializer_list il, Args&&... args) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (il, std::forward(args)...); - } - template ::value>* = nullptr, - detail::enable_forward_value* = nullptr> - constexpr optional(U&& u) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (std::forward(u)); - } - - template ::value>* = nullptr, - detail::enable_forward_value* = nullptr> - constexpr explicit optional(U&& u) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (std::forward(u)); - } - - template * = nullptr, - tl::enable_if_t::value>* = nullptr> - optional(const optional& rhs) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (rhs.value()); - } - - template * = nullptr, - tl::enable_if_t::value>* = nullptr> - optional(const optional& rhs) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (rhs.value()); - } - - template * = nullptr, - tl::enable_if_t::value>* = nullptr> - optional(optional&& rhs) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (std::move(rhs.value())); - } - - - template * = nullptr, - enable_if_t::value>* = nullptr> - explicit optional(optional&& rhs) { - this->m_has_value = true; - new (std::addressof(this->m_value)) T (std::move(rhs.value())); - } - - // [optional.dtor], destructor - ~optional() = default; - - // [optional.assign], assignment - optional& operator=(nullopt_t) noexcept { - if (has_value()) { - this->m_value.~T(); - this->m_has_value = false; - } - } - - // TODO conditionally delete, check exception guarantee - optional& operator=(const optional& rhs) { - if (has_value()) { if (rhs.has_value()) { - this->m_value = rhs.m_value; - } - else { - this->m_value.~T(); - this->m_has_value = false; + new (std::addressof(this->m_value)) T (rhs.m_value); + this->m_has_value = true; } } - if (rhs.has_value()) { - new (std::addressof(this->m_value)) T (rhs.m_value); - this->m_has_value = true; - } - } + // TODO conditionally delete, check exception guarantee + optional& operator=(optional&& rhs) noexcept { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = std::move(rhs.m_value); + } + else { + this->m_value.~T(); + this->m_has_value = false; + } + } - // TODO conditionally delete, check exception guarantee - optional& operator=(optional&& rhs) noexcept { - if (has_value()) { if (rhs.has_value()) { - this->m_value = std::move(rhs.m_value); - } - else { - this->m_value.~T(); - this->m_has_value = false; + new (std::addressof(this->m_value)) T (std::move(rhs.m_value)); + this->m_has_value = true; } } - if (rhs.has_value()) { - new (std::addressof(this->m_value)) T (std::move(rhs.m_value)); - this->m_has_value = true; - } - } - - // TODO conditionally delete, check exception guarantee - template * = nullptr> + // TODO conditionally delete, check exception guarantee + template * = nullptr> optional& operator=(U&& u) { - if (has_value()) { - this->m_value = std::forward(u); + if (has_value()) { + this->m_value = std::forward(u); + } + else { + new (std::addressof(this->m_value)) T (std::forward(u)); + this->m_has_value = true; + } } - else { - new (std::addressof(this->m_value)) T (std::forward(u)); - this->m_has_value = true; - } - } - // TODO SFINAE, check exception guarantee - template * = nullptr> + // TODO check exception guarantee + template * = nullptr> optional& operator=(const optional& rhs) { - if (has_value()) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = rhs.m_value; + } + else { + this->m_value.~T(); + this->m_has_value = false; + } + } + if (rhs.has_value()) { - this->m_value = rhs.m_value; - } - else { - this->m_value.~T(); - this->m_has_value = false; + new (std::addressof(this->m_value)) T (rhs.m_value); + this->m_has_value = true; } } - if (rhs.has_value()) { - new (std::addressof(this->m_value)) T (rhs.m_value); - this->m_has_value = true; - } - } + // TODO check exception guarantee + template * = nullptr> + optional& operator=(optional&& rhs) { + if (has_value()) { + if (rhs.has_value()) { + this->m_value = std::move(rhs.m_value); + } + else { + this->m_value.~T(); + this->m_has_value = false; + } + } - // TODO SFINAE, check exception guarantee - template * = nullptr> - optional& operator=(optional&& rhs) { - if (has_value()) { if (rhs.has_value()) { - this->m_value = std::move(rhs.m_value); - } - else { - this->m_value.~T(); - this->m_has_value = false; + new (std::addressof(this->m_value)) T (std::move(rhs.m_value)); + this->m_has_value = true; } } - if (rhs.has_value()) { - new (std::addressof(this->m_value)) T (std::move(rhs.m_value)); - this->m_has_value = true; + template T& emplace(Args&&... args) { + static_assert(std::is_constructible::value, + "T must be constructible with Args"); + + *this = nullopt; + new (std::addressof(this->m_value)) T(std::forward(args)...); } - } - template T& emplace(Args&&... args) { - static_assert(std::is_constructible::value, - "T must be constructible with Args"); + template + enable_if_t&, Args&&...>::value, T&> + emplace(std::initializer_list il, Args&&... args) { + *this = nullopt; + new (std::addressof(this->m_value)) T(il, std::forward(args)...); + } - *this = nullopt; - new (std::addressof(this->m_value)) T(std::forward(args)...); - } - - template - tl::enable_if_t&, Args&&...>::value, T&> - emplace(std::initializer_list il, Args&&... args) { - *this = nullopt; - new (std::addressof(this->m_value)) T(il, std::forward(args)...); - } - - // [optional.swap], swap - void swap(optional& rhs) - noexcept(std::is_nothrow_move_constructible::value && is_nothrow_swappable::value) - { - if (has_value()) { - if (rhs.has_value()) { - using std::swap; - swap(value(), rhs.value()); + // [optional.swap], swap + void swap(optional& rhs) + noexcept(std::is_nothrow_move_constructible::value && detail::is_nothrow_swappable::value) + { + if (has_value()) { + if (rhs.has_value()) { + using std::swap; + swap(value(), rhs.value()); + } + else { + new (&rhs.m_value) T (std::move(this->m_value)); + this->m_value.T::~T(); + } } - else { - new (&rhs.m_value) T (std::move(this->m_value)); - this->m_value.T::~T(); + else if (rhs.has_value()) { + new (std::addressof(this->m_value)) T (std::move(rhs.m_value)); + rhs.m_value.T::~T(); } } - else if (rhs.has_value()) { - new (std::addressof(this->m_value)) T (std::move(rhs.m_value)); - rhs.m_value.T::~T(); + + // [optional.observe], observers + constexpr const T* operator->() const { + return std::addressof(this->m_value); + } + constexpr T* operator->() { + return std::addressof(this->m_value); + } + constexpr const T& operator*() const& { + return this->m_value; + } + constexpr T& operator*() & { + return this->m_value; + } + constexpr T&& operator*() && { + return std::move(this->m_value); + } + constexpr const T&& operator*() const&& { + return std::move(this->m_value); + } + constexpr explicit operator bool() const noexcept { + return this->m_has_value; + } + constexpr bool has_value() const noexcept { + return this->m_has_value; + } + constexpr const T& value() const& { + if (has_value()) return this->m_value; + throw bad_optional_access(); + } + constexpr T& value() & { + if (has_value()) return this->m_value; + throw bad_optional_access(); + } + constexpr T&& value() && { + if (has_value()) return std::move(this->m_value); + throw bad_optional_access(); + } + constexpr const T&& value() const&& { + if (has_value()) return std::move(this->m_value); + throw bad_optional_access(); + } + template constexpr T value_or(U&& u) const& { + static_assert(std::is_copy_constructible::value && std::is_convertible::value, + "T must be copy constructible and convertible from U"); + return has_value() ? value() : static_cast(std::forward(u)); + } + template constexpr T value_or(U&& u) && { + static_assert(std::is_move_constructible::value && std::is_convertible::value, + "T must be move constructible and convertible from U"); + return has_value() ? value() : static_cast(std::forward(u)); } - } - // [optional.observe], observers - constexpr const T* operator->() const { - return std::addressof(this->m_value); - } - constexpr T* operator->() { - return std::addressof(this->m_value); - } - constexpr const T& operator*() const& { - return this->m_value; - } - constexpr T& operator*() & { - return this->m_value; - } - constexpr T&& operator*() && { - return std::move(this->m_value); - } - constexpr const T&& operator*() const&& { - return std::move(this->m_value); - } - constexpr explicit operator bool() const noexcept { - return this->m_has_value; - } - constexpr bool has_value() const noexcept { - return this->m_has_value; - } - constexpr const T& value() const& { - if (has_value()) return this->m_value; - throw bad_optional_access(); - } - constexpr T& value() & { - if (has_value()) return this->m_value; - throw bad_optional_access(); - } - constexpr T&& value() && { - if (has_value()) return std::move(this->m_value); - throw bad_optional_access(); - } - constexpr const T&& value() const&& { - if (has_value()) return std::move(this->m_value); - throw bad_optional_access(); - } - template constexpr T value_or(U&& u) const& { - static_assert(std::is_copy_constructible::value && std::is_convertible::value, - "T must be copy constructible and convertible from U"); - return has_value() ? value() : static_cast(std::forward(u)); - } - template constexpr T value_or(U&& u) && { - static_assert(std::is_move_constructible::value && std::is_convertible::value, - "T must be move constructible and convertible from U"); - return has_value() ? value() : static_cast(std::forward(u)); - } + // [optional.mod], modifiers + void reset() noexcept; - // [optional.mod], modifiers - void reset() noexcept; + private: - private: - - }; + }; }