55 struct sentinel_optional
57 using sentinel_type =
decltype(SENTINEL);
59 static_assert(EQ{}(SENTINEL, SENTINEL),
"Sentinel value must equal itself under the equal operation given in the template parameter EQ");
61 constexpr sentinel_optional()
noexcept {}
62 constexpr sentinel_optional(std::nullopt_t)
noexcept {}
64 template <
class... TYPES, std::enable_if_t<std::is_constructible_v<T, TYPES...>,
int> = 0>
65 constexpr explicit sentinel_optional(std::in_place_t, TYPES&&... args)
noexcept(std::is_nothrow_constructible_v<T, TYPES...>)
66 : m_value(std::forward<TYPES>(args)...)
70 template <
class U = T, std::enable_if_t<
71 !std::is_same_v<remove_cvref_t<U>, sentinel_optional> &&
72 !std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
73 !std::is_same_v<std::remove_cv_t<U>,
bool> &&
74 std::is_constructible_v<T, U>
76 constexpr sentinel_optional(U&&
right)
noexcept(std::is_nothrow_constructible_v<T, U>)
77 : m_value(std::forward<U>(
right))
81 template <
class U, std::enable_if_t<std::is_constructible_v<T, const U&>,
int> = 0>
82 constexpr explicit sentinel_optional(
const sentinel_optional<U>&
right)
noexcept(std::is_nothrow_constructible_v<T, const U&>)
85 this->m_value = *
right;
88 template <
class U, std::enable_if_t<std::is_constructible_v<T, U>,
int> = 0>
89 constexpr explicit sentinel_optional(sentinel_optional<U>&&
right)
noexcept(std::is_nothrow_constructible_v<T, U>)
92 this->m_value = std::move(*
right);
95 constexpr sentinel_optional& operator=(std::nullopt_t)
noexcept {
100 template <
class U = T, std::enable_if_t<
101 !std::is_same_v<sentinel_optional, remove_cvref_t<U>> &&
102 std::is_constructible_v<T, U> &&
103 std::is_assignable_v<T&, U>,
105 constexpr sentinel_optional& operator=(U&&
right)
noexcept(std::is_nothrow_assignable_v<T&, U> && std::is_nothrow_constructible_v<T, U>)
107 this->m_value = std::forward<U>(
right);
111 template <
class U, std::enable_if_t<
113 std::is_same_v<T, U> ||
114 std::is_assignable_v<T&, sentinel_optional<U>&> ||
115 std::is_assignable_v<T&, const sentinel_optional<U>&> ||
116 std::is_assignable_v<T&, const sentinel_optional<U>> ||
117 std::is_assignable_v<T&, sentinel_optional<U>>
119 std::is_constructible_v<T, const U&> &&
120 std::is_assignable_v<T&, const U&>,
122 constexpr sentinel_optional&
operator=(
const sentinel_optional<U>&
right)
noexcept(std::is_nothrow_assignable_v<T&, const U&> && std::is_nothrow_constructible_v<T, const U&>)
125 this->m_value = *
right;
132 template <
class U, std::enable_if_t<
134 std::is_same_v<T, U> ||
135 std::is_assignable_v<T&, sentinel_optional<U>&> ||
136 std::is_assignable_v<T&, const sentinel_optional<U>&> ||
137 std::is_assignable_v<T&, const sentinel_optional<U>> ||
138 std::is_assignable_v<T&, sentinel_optional<U>>
140 std::is_constructible_v<T, U> &&
141 std::is_assignable_v<T&, U>,
143 constexpr sentinel_optional&
operator=(sentinel_optional<U>&&
right)
noexcept(std::is_nothrow_assignable_v<T&, U>&& std::is_nothrow_constructible_v<T, U>)
146 this->m_value = std::move(*
right);
153 template <
class... TYPES>
154 constexpr T& emplace(TYPES&&... args)
noexcept(std::is_nothrow_constructible_v<T, TYPES...>)
157 return this->m_value = T(std::forward<TYPES>(args)...);
160 inline constexpr void assert_value()
const {
if (!has_value())
throw std::bad_optional_access(); }
162 [[nodiscard]]
constexpr const T* operator->()
const
164 this->assert_value();
165 return std::addressof(this->m_value);
167 [[nodiscard]]
constexpr T* operator->()
169 this->assert_value();
170 return std::addressof(this->m_value);
173 [[nodiscard]]
constexpr T& operator*() &
175 this->assert_value();
176 return this->m_value;
179 [[nodiscard]]
constexpr const T& operator*()
const&
181 this->assert_value();
182 return this->m_value;
185 [[nodiscard]]
constexpr T&& operator*() &&
187 this->assert_value();
188 return std::move(this->m_value);
191 [[nodiscard]]
constexpr const T&& operator*()
const&&
193 this->assert_value();
194 return std::move(this->m_value);
197 [[nodiscard]]
constexpr bool has_value()
const noexcept {
return !EQ{}(this->m_value, SENTINEL); }
198 constexpr explicit operator bool()
const noexcept {
return has_value(); }
200 [[nodiscard]]
constexpr const T& value()
const& {
201 this->assert_value();
202 return this->m_value;
204 [[nodiscard]]
constexpr T& value()& {
205 this->assert_value();
206 return this->m_value;
208 [[nodiscard]]
constexpr T&& value()&& {
209 this->assert_value();
210 return std::move(this->m_value);
212 [[nodiscard]]
constexpr const T&& value()
const&& {
213 this->assert_value();
214 return std::move(this->m_value);
219 return this->m_value;
223 return this->m_value;
227 return std::move(this->m_value);
230 [[nodiscard]]
constexpr const T&&
raw_value() const && {
231 return std::move(this->m_value);
265 constexpr void reset() noexcept { this->m_value = SENTINEL; }
267 [[nodiscard]]
friend constexpr bool operator==(
const sentinel_optional& lhs,
const sentinel_optional& rhs)
269 return lhs.has_value() != rhs.has_value() ? false : (lhs.has_value() ==
false ?
true : lhs.m_value == rhs.m_value);
271 [[nodiscard]]
friend constexpr bool operator!=(
const sentinel_optional& lhs,
const sentinel_optional& rhs)
273 return lhs.has_value() != rhs.has_value() ? true : (lhs.has_value() ==
false ?
false : lhs.m_value != rhs.m_value);
275 [[nodiscard]]
friend constexpr bool operator<(
const sentinel_optional& lhs,
const sentinel_optional& rhs)
277 return !rhs ? false : (!lhs ? true : *lhs < *rhs);
279 [[nodiscard]]
friend constexpr bool operator<=(
const sentinel_optional & lhs,
const sentinel_optional & rhs)
281 return !lhs ? true : (!rhs ? false : *lhs <= *rhs);
283 [[nodiscard]]
friend constexpr bool operator>(
const sentinel_optional& lhs,
const sentinel_optional & rhs)
285 return !lhs ? false : (!rhs ? true : *lhs > *rhs);
287 [[nodiscard]]
friend constexpr bool operator>=(
const sentinel_optional& lhs,
const sentinel_optional& rhs)
289 return !rhs ? true : (!lhs ? false : *lhs >= *rhs);
291 [[nodiscard]]
friend constexpr auto operator<=>(
const sentinel_optional& lhs,
const sentinel_optional& rhs)
293 return lhs && rhs ? *lhs <=> *rhs : lhs.has_value() <=> rhs.has_value();
296 [[nodiscard]]
friend constexpr bool operator==(
const sentinel_optional& opt, std::nullopt_t) {
return !opt; }
297 [[nodiscard]]
friend constexpr auto operator<=>(
const sentinel_optional& opt, std::nullopt_t) {
return opt.has_value() <=>
false; }
301 T m_value = SENTINEL;