111 : optional_detail::optional_base<T>
112 , implicit_constructor_base<T>
113 , generic_ordering_from_three_way_compare_and_equals<optional<T>>
114 ,
public optional_detail::optional_value_interface<optional<T>> {
117 using base_type = optional_detail::optional_base<T>;
122 using storage_type =
typename base_type::storage_type;
126 using compare_base = generic_ordering_from_three_way_compare_and_equals<optional<T>>;
129 using constructor_base = implicit_constructor_base<T>;
132 using interface_base = optional_detail::optional_value_interface<optional<T>>;
134 static_assert(!has_overloaded_address_operator_v<T>,
"Stored type must not have an overloaded address operator");
140 using value_type = T;
146 constexpr optional()
noexcept
154 ~optional() =
default;
160 constexpr optional(nullopt_t)
noexcept
168 constexpr optional(optional
const&)
noexcept(std::is_nothrow_copy_constructible<T>::value) =
default;
173 constexpr optional(optional&&)
noexcept(
175 std::is_nothrow_move_constructible<T>::value
184 std::enable_if_t<!std::is_same<optional, remove_cvref_t<U>>::value>,
185 std::enable_if_t<!std::is_same<nullopt_t, remove_cvref_t<U>>::value>,
186 std::enable_if_t<std::is_constructible<T, U&&>::value>> =
nullptr>
188 constexpr optional(U&& other)
noexcept(std::is_nothrow_constructible<T, U&&>::value)
189 : base_type(std::forward<U>(other)),
199 std::enable_if_t<std::is_constructible<T, U>::value>,
200 std::enable_if_t<!std::is_constructible<T, optional<U>>::value>,
201 std::enable_if_t<!std::is_constructible<T, optional<U>&>::value>,
202 std::enable_if_t<!std::is_constructible<T, optional<U>
const&>::value>> =
nullptr>
204 constexpr optional(optional<U>&& other)
noexcept(
noexcept(T(std::declval<U&&>())))
205 : base_type(std::move(other)),
216 std::enable_if_t<std::is_constructible<T, U>::value>,
217 std::enable_if_t<!std::is_constructible<T, optional<U>>::value>,
218 std::enable_if_t<!std::is_constructible<T, optional<U>&>::value>,
219 std::enable_if_t<!std::is_constructible<T, optional<U>
const&>::value>> =
nullptr>
221 constexpr optional(optional<U>
const& other)
noexcept(
noexcept(T(std::declval<U
const&>())))
233 constraints<std::enable_if_t<
sizeof(
decltype(T(std::declval<Args>()...))) != 0>> =
nullptr>
235 constexpr optional(in_place_t, Args&&... args)
noexcept(
noexcept(T(std::forward<Args>(args)...)))
236 : base_type(in_place, std::forward<Args>(args)...),
245 constexpr auto operator=(nullopt_t)
noexcept -> optional& {
255 constexpr auto operator=(optional
const& other
256 )
noexcept(std::is_nothrow_copy_constructible<T>::value && std::is_nothrow_copy_assignable<T>::value) -> optional& {
257 if (
this != &other) {
258 internal_do_assign(other);
267 constexpr auto operator=(optional&& other)
269 noexcept(std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value) -> optional& {
270 internal_do_assign(std::move(other));
280 std::enable_if_t<!std::is_same<remove_cvref_t<U>, optional>::value>,
281 std::enable_if_t<std::is_constructible<T, U>::value>,
282 std::enable_if_t<std::is_assignable<T, U>::value>> =
nullptr>
283 auto operator=(U&& other)
noexcept(std::is_nothrow_assignable<T, U>::value&&
noexcept(
284 std::declval<optional&>().construct_from(std::forward<U>(other))
286 if (
this->has_value()) {
287 **
this = std::forward<U>(other);
289 construct_from(std::forward<U>(other));
297 using base_type::has_value;
302 constexpr explicit operator
bool()
const noexcept {
return this->has_value(); }
312 constexpr auto operator*()
const&
noexcept -> T
const& {
313 ARENE_PRECONDITION(
this->has_value());
315 return this->storage().value;
317 constexpr auto operator*() &
noexcept -> T& {
318 ARENE_PRECONDITION(
this->has_value());
320 return this->storage().value;
322 constexpr auto operator*()
const&&
noexcept -> T
const&& {
323 ARENE_PRECONDITION(
this->has_value());
326 return std::move(
this->storage().value);
329 constexpr auto operator*() &&
noexcept -> T&& {
330 ARENE_PRECONDITION(
this->has_value());
332 return std::move(
this->storage().value);
346 constexpr auto operator->()
const noexcept -> T
const* {
347 ARENE_PRECONDITION(
this->has_value());
350 constexpr auto operator->()
noexcept -> T* {
351 ARENE_PRECONDITION(
this->has_value());
372 std::enable_if_t<std::is_copy_constructible<R>::value>,
373 std::enable_if_t<std::is_convertible<U, R>::value>> =
nullptr>
374 constexpr auto value_or(U&& default_value
375 )
const&
noexcept(
noexcept(optional::value_or(std::declval<optional
const&>(), std::forward<U>(default_value))))
377 return optional::value_or(*
this, std::forward<U>(default_value));
383 std::enable_if_t<std::is_move_constructible<R>::value>,
384 std::enable_if_t<std::is_convertible<U, R>::value>> =
nullptr>
385 constexpr auto value_or(U&& default_value
386 ) &&
noexcept(
noexcept(optional::value_or(std::declval<optional&&>(), std::forward<U>(default_value)))) -> T {
387 return optional::value_or(std::move(*
this), std::forward<U>(default_value));
406 std::enable_if_t<std::is_copy_constructible<R>::value>,
407 std::enable_if_t<std::is_convertible<invoke_result_t<F>, R>::value>> =
nullptr>
408 constexpr auto value_or_else(F&& default_generator)
const&
noexcept(
409 noexcept(optional::value_or_else(std::declval<optional
const&>(), std::forward<F>(default_generator)))
411 return optional::value_or_else(*
this, std::forward<F>(default_generator));
417 std::enable_if_t<std::is_move_constructible<R>::value>,
418 std::enable_if_t<std::is_convertible<invoke_result_t<F>, R>::value>> =
nullptr>
419 constexpr auto value_or_else(F&& default_generator
420 ) &&
noexcept(
noexcept(optional::value_or_else(std::declval<optional&&>(), std::forward<F>(default_generator))))
422 return optional::value_or_else(std::move(*
this), std::forward<F>(default_generator));
431 template <
typename... Args>
432 constexpr void emplace(Args&&... args
433 )
noexcept(
noexcept(std::declval<optional<T>>().construct_from(std::forward<Args>(args)...))) {
435 construct_from(std::forward<Args>(args)...);
448 template <
typename F>
449 constexpr auto and_then(F&& handle_value) & -> invoke_result_t<F, T&> {
450 static_assert(is_invocable_v<F, T&>,
"handle_value must be invocable with value_type.");
452 is_instantiation_of_v<invoke_result_t<F, T&>, ::arene::base::optional>,
453 "handle_value must return an optional"
455 return optional::and_then(*
this, std::forward<F>(handle_value));
457 template <
typename F>
458 constexpr auto and_then(F&& handle_value)
const& -> invoke_result_t<F, T
const&> {
459 static_assert(is_invocable_v<F, T
const&>,
"handle_value must be invocable with value_type.");
461 is_instantiation_of_v<invoke_result_t<F, T
const&>, ::arene::base::optional>,
462 "handle_value must return an optional"
464 return optional::and_then(*
this, std::forward<F>(handle_value));
466 template <
typename F>
467 constexpr auto and_then(F&& handle_value) && -> invoke_result_t<F, T&&> {
468 static_assert(is_invocable_v<F, T&&>,
"handle_value must be invocable with value_type.");
470 is_instantiation_of_v<invoke_result_t<F, T&&>, ::arene::base::optional>,
471 "handle_value must return an optional"
473 return optional::and_then(std::move(*
this), std::forward<F>(handle_value));
475 template <
typename F>
476 constexpr auto and_then(F&& handle_value)
const&& -> invoke_result_t<F, T
const&&> {
477 static_assert(is_invocable_v<F, T
const&&>,
"handle_value must be invocable with value_type.");
479 is_instantiation_of_v<invoke_result_t<F, T
const&&>, ::arene::base::optional>,
480 "handle_value must return an optional"
483 return optional::and_then(std::move(*
this), std::forward<F>(handle_value));
502 constraints<std::enable_if_t<is_invocable_v<F>>, std::enable_if_t<std::is_copy_constructible<R>::value>> =
504 constexpr auto or_else(F&& handle_null)
const& -> optional<T> {
506 decays_to_v<invoke_result_t<F>, optional<T>>,
507 "handle_null must be void invocable and return an optional with the same type as this."
509 return optional::or_else(*
this, std::forward<F>(handle_null));
514 constraints<std::enable_if_t<is_invocable_v<F>>, std::enable_if_t<std::is_move_constructible<R>::value>> =
516 constexpr auto or_else(F&& handle_null) && -> optional<T> {
518 decays_to_v<invoke_result_t<F>, optional<T>>,
519 "handle_null must be void invocable and return an optional with the same type as this."
521 return optional::or_else(std::move(*
this), std::forward<F>(handle_null));
539 template <
typename F>
540 constexpr auto transform(F&& value_transformer) & -> optional<invoke_result_t<F, T&>> {
541 static_assert(is_invocable_v<F, T&>,
"value_transformer must be invocable with value_type.");
543 substitution_succeeds<::arene::base::optional, invoke_result_t<F, T&>>,
544 "value_transformer must return a type that can be validly placed in an optional"
546 return optional::transform(*
this, std::forward<F>(value_transformer));
548 template <
typename F>
549 constexpr auto transform(F&& value_transformer)
const& -> optional<invoke_result_t<F, T
const&>> {
550 static_assert(is_invocable_v<F, T
const&>,
"value_transformer must be invocable with value_type.");
552 substitution_succeeds<::arene::base::optional, invoke_result_t<F, T
const&>>,
553 "value_transformer must return a type that can be validly placed in an optional"
555 return optional::transform(*
this, std::forward<F>(value_transformer));
557 template <
typename F>
558 constexpr auto transform(F&& value_transformer) && -> optional<invoke_result_t<F, T&&>> {
559 static_assert(is_invocable_v<F, T&&>,
"value_transformer must be invocable with value_type.");
561 substitution_succeeds<::arene::base::optional, invoke_result_t<F, T&&>>,
562 "value_transformer must return a type that can be validly placed in an optional"
564 return optional::transform(std::move(*
this), std::forward<F>(value_transformer));
566 template <
typename F>
567 constexpr auto transform(F&& value_transformer)
const&& -> optional<invoke_result_t<F, T
const&&>> {
568 static_assert(is_invocable_v<F, T
const&&>,
"value_transformer must be invocable with value_type.");
570 substitution_succeeds<::arene::base::optional, invoke_result_t<F, T
const&&>>,
571 "value_transformer must return a type that can be validly placed in an optional"
574 return optional::transform(std::move(*
this), std::forward<F>(value_transformer));
594 constraints<std::enable_if_t<is_swappable_v<U>>, std::enable_if_t<std::is_move_constructible<U>::value>> =
596 constexpr void swap(optional& other)
noexcept(
597 is_nothrow_swappable_v<U> && std::is_nothrow_move_constructible<U>::value
599 if (
this->has_value() && other.has_value()) {
600 ::arene::base::swap(**
this, *other);
601 }
else if (
this->has_value()) {
602 other.construct_from(std::move(**
this));
605 construct_from(std::move(*other));
624 constraints<std::enable_if_t<is_swappable_v<U>>, std::enable_if_t<std::is_move_constructible<U>::value>> =
626 friend constexpr void swap(optional& lhs, optional& rhs)
noexcept(
noexcept(lhs.swap(rhs))) {
634 using base_type::reset;
641 static constexpr auto three_way_compare(optional
const& lhs, nullopt_t)
noexcept -> strong_ordering {
642 return lhs ? strong_ordering::greater : strong_ordering::equal;
655 template <
typename U, constraints<std::enable_if_t<!has_fast_inequality_check_v<T, U>>> =
nullptr>
656 static constexpr auto fast_inequality_check(optional
const& lhs, optional<U>
const& rhs)
noexcept
657 -> inequality_heuristic {
658 return (lhs.has_value() != rhs.has_value()) ? inequality_heuristic::definitely_not_equal
659 : inequality_heuristic::may_be_equal_or_not_equal;
673 template <
typename U, constraints<std::enable_if_t<has_fast_inequality_check_v<T, U>>> =
nullptr>
674 static constexpr auto fast_inequality_check(optional
const& lhs, optional<U>
const& rhs)
noexcept
675 -> inequality_heuristic {
676 if (lhs.has_value() != rhs.has_value()) {
677 return inequality_heuristic::definitely_not_equal;
680 return inequality_heuristic::may_be_equal_or_not_equal;
682 return T::fast_inequality_check(*lhs, *rhs);
702 std::enable_if_t<std::is_same<Self, optional>::value>,
703 std::enable_if_t<compare_three_way_supported_v<T, U>>> =
nullptr>
704 static constexpr auto three_way_compare(Self
const& lhs, optional<U>
const& rhs)
noexcept -> strong_ordering {
707 return compare_three_way{}(*lhs, *rhs);
709 return strong_ordering::greater;
712 return strong_ordering::less;
714 return strong_ordering::equal;
729 std::enable_if_t<!has_fast_inequality_check_v<T, U>>,
730 std::enable_if_t<!std::is_same<U, nullopt_t>::value>> =
nullptr>
731 static constexpr auto fast_inequality_check(optional
const& lhs, U
const&)
noexcept -> inequality_heuristic {
732 return !lhs ? inequality_heuristic::definitely_not_equal : inequality_heuristic::may_be_equal_or_not_equal;
748 std::enable_if_t<has_fast_inequality_check_v<T, U>>,
749 std::enable_if_t<!std::is_same<U, nullopt_t>::value>> =
nullptr>
750 static constexpr auto fast_inequality_check(optional
const& lhs, U
const& rhs)
noexcept -> inequality_heuristic {
752 return inequality_heuristic::definitely_not_equal;
754 return T::fast_inequality_check(*lhs, rhs);
772 std::enable_if_t<std::is_same<Self, optional>::value>,
773 std::enable_if_t<!optional_detail::is_optional<U>::value>,
774 std::enable_if_t<compare_three_way_supported_v<T, U>>> =
nullptr>
775 static constexpr auto three_way_compare(Self
const& lhs, U
const& rhs)
noexcept -> strong_ordering {
777 return compare_three_way{}(*lhs, rhs);
779 return strong_ordering::less;
783 ARENE_IGNORE_START();
784 ARENE_IGNORE_ALL(
"-Wfloat-equal",
"Can only suppress this here, not in user code; std::vector does the same thing");
785 ARENE_IGNORE_ALL(
"-Wsign-compare",
"Can only suppress this here, not in user code; std::vector does the same thing");
802 std::enable_if_t<std::is_same<Self, optional>::value>,
803 std::enable_if_t<!optional_detail::is_optional<U>::value>,
804 std::enable_if_t<is_equality_comparable_v<T, U>>> =
nullptr>
805 friend constexpr auto operator==(Self
const& lhs, U
const& rhs)
noexcept ->
bool {
832 std::enable_if_t<std::is_same<Self, optional>::value>,
833 std::enable_if_t<!optional_detail::is_optional<U>::value>,
834 std::enable_if_t<is_equality_comparable_v<T, U>>> =
nullptr>
835 friend constexpr auto operator==(Self
const& lhs, optional<U>
const& rhs)
noexcept ->
bool {
853 friend constexpr auto operator==(optional
const& lhs, nullopt_t)
noexcept ->
bool {
return !lhs.has_value(); }
858 friend constexpr auto operator!=(optional
const& lhs, nullopt_t)
noexcept ->
bool {
return lhs.has_value(); }
863 friend constexpr auto operator!=(nullopt_t, optional
const& rhs)
noexcept ->
bool {
return rhs.has_value(); }
879 std::enable_if_t<std::is_same<Self, optional>::value>,
880 std::enable_if_t<!optional_detail::is_optional<U>::value>,
881 std::enable_if_t<is_equality_comparable_v<T, U>>> =
nullptr>
882 friend constexpr auto operator!=(Self
const& lhs, optional<U>
const& rhs)
noexcept ->
bool {
883 return !(lhs == rhs);
897 constraints<std::enable_if_t<
noexcept(storage_type(in_place, std::declval<Args>()...))>> =
nullptr>
898 void construct_from(Args&&... args)
noexcept {
900 this->storage().~storage_type();
901 construct_at(&
this->storage(), in_place, std::forward<Args>(args)...);
902 this->set_has_value();
912 constraints<std::enable_if_t<!
noexcept(storage_type(in_place, std::declval<Args>()...))>> =
nullptr>
913 void construct_from(Args&&... args) {
920 auto make_empty_on_throw = on_scope_exit([
this]()
noexcept { construct_at(&
this->storage()); });
924 construct_at(&
this->storage(), in_place, std::forward<Args>(args)...);
925 this->set_has_value();
926 make_empty_on_throw.cancel();
932 template <
typename OtherOptional>
933 constexpr void internal_do_assign(OtherOptional&& other)
noexcept(
934 std::is_nothrow_constructible<T,
decltype(*std::forward<OtherOptional>(other))>::value &&
935 std::is_nothrow_assignable<T&,
decltype(*std::forward<OtherOptional>(other))>::value
937 if (
this->has_value() && other.has_value()) {
938 **
this = *std::forward<OtherOptional>(other);
939 }
else if (
this->has_value()) {
941 }
else if (other.has_value()) {
942 construct_from(*std::forward<OtherOptional>(other));
950 template <
typename U>
951 friend class optional;
963 template <
typename Self,
typename U, constraints<std::enable_if_t<decays_to_v<Self, optional>>> =
nullptr>
964 static constexpr auto value_or(Self&& self, U&& default_value)
noexcept(
noexcept(T{default_value}
965 ) &&
noexcept(T{*std::forward<Self>(self)})) -> T {
966 return self.has_value() ?
static_cast<T>(forward_like<Self>(std::forward<Self>(self).storage().value))
967 :
static_cast<T>(std::forward<U>(default_value));
978 template <
typename Self,
typename F, constraints<std::enable_if_t<decays_to_v<Self, optional>>> =
nullptr>
979 static constexpr auto value_or_else(Self&& self, F&& default_generator)
noexcept(
noexcept(T{
980 ::arene::base::invoke(std::forward<F>(default_generator))
981 }) &&
noexcept(T{*std::forward<Self>(self)})) -> T {
982 return self.has_value() ?
static_cast<T>(forward_like<Self>(std::forward<Self>(self).storage().value))
983 :
static_cast<T>(::arene::base::invoke(std::forward<F>(default_generator)));
996 template <
typename Self,
typename F, constraints<std::enable_if_t<decays_to_v<Self, optional>>> =
nullptr>
997 static constexpr auto and_then(Self&& self, F&& handle_value)
998 -> invoke_result_t<F,
decltype(forward_like<Self>(std::declval<Self&&>().storage().value))> {
999 using f_optional_t = invoke_result_t<F,
decltype(forward_like<Self>(std::forward<Self>(self).storage().value))>;
1000 if (self.has_value()) {
1001 return ::arene::base::invoke(
1002 std::forward<F>(handle_value),
1003 forward_like<Self>(std::forward<Self>(self).storage().value)
1006 return f_optional_t{};
1018 template <
typename Self,
typename F, constraints<std::enable_if_t<decays_to_v<Self, optional>>> =
nullptr>
1019 static constexpr auto or_else(Self&& self, F&& handle_null) -> optional<T> {
1020 if (self.has_value()) {
1021 return {std::forward<Self>(self)};
1023 return ::arene::base::invoke(std::forward<F>(handle_null));
1037 template <
typename Self,
typename F, constraints<std::enable_if_t<decays_to_v<Self, optional>>> =
nullptr>
1038 static constexpr auto transform(Self&& self, F&& value_transformer)
1039 -> optional<invoke_result_t<F,
decltype(forward_like<Self>(std::declval<Self&&>().storage().value))>> {
1040 using f_return_t = invoke_result_t<F,
decltype(forward_like<Self>(std::forward<Self>(self).storage().value))>;
1041 using optional_t = optional<f_return_t>;
1042 if (self.has_value()) {
1043 return optional_t{::arene::base::invoke(
1044 std::forward<F>(value_transformer),
1045 forward_like<Self>(std::forward<Self>(self).storage().value)
1048 return optional_t{};