[libcxx-commits] [libcxx] 0f985af - [libc++] Refactor `optional<T>` and `optional<T&>` base classes (#215012)
via libcxx-commits
libcxx-commits at lists.llvm.org
Sun Aug 9 23:53:26 PDT 2026
Author: William Tran-Viet
Date: 2026-08-10T14:53:21+08:00
New Revision: 0f985af790f8d542b126de8c3d219fc591df9652
URL: https://github.com/llvm/llvm-project/commit/0f985af790f8d542b126de8c3d219fc591df9652
DIFF: https://github.com/llvm/llvm-project/commit/0f985af790f8d542b126de8c3d219fc591df9652.diff
LOG: [libc++] Refactor `optional<T>` and `optional<T&>` base classes (#215012)
- Remove the shared `__optional_storage_base` base class and associated
partial specializations to handle the `T&` case in `optional<T>`
- As a consequence, the `static_assert`s that check for reference types
in `optional<T>` need to be moved up to the base class as the
`is_object_v` check is tripped, otherwise.
- Directly inline base class functions for both that used to exist to
accommodate a "dual-mode" (`T` and `T&`) `optional`.
Added:
Modified:
libcxx/include/__optional/common.h
libcxx/include/__optional/optional.h
libcxx/include/__optional/optional_ref.h
Removed:
################################################################################
diff --git a/libcxx/include/__optional/common.h b/libcxx/include/__optional/common.h
index 5ddb993f3e376..26031f658a904 100644
--- a/libcxx/include/__optional/common.h
+++ b/libcxx/include/__optional/common.h
@@ -64,9 +64,6 @@ inline constexpr bool __is_std_optional_v = false;
template <class _Tp>
inline constexpr bool __is_std_optional_v<optional<_Tp>> = true;
-template <class _Tp, bool = is_reference<_Tp>::value>
-struct __optional_storage_base;
-
# if _LIBCPP_STD_VER < 26
template <class _Tp>
inline constexpr bool __is_valid_optional_contained_type = is_object_v<_Tp>;
diff --git a/libcxx/include/__optional/optional.h b/libcxx/include/__optional/optional.h
index 8d6a9fbed8599..7c2ab7574e8cb 100644
--- a/libcxx/include/__optional/optional.h
+++ b/libcxx/include/__optional/optional.h
@@ -73,6 +73,11 @@ struct __optional_destruct_base;
template <class _Tp>
struct __optional_destruct_base<_Tp, false> {
typedef _Tp value_type;
+# if _LIBCPP_STD_VER >= 26
+ static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed");
+# else
+ static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed");
+# endif
static_assert(is_object_v<value_type>, "instantiation of optional with a non-object type is undefined behavior");
union {
char __null_state_;
@@ -109,6 +114,11 @@ struct __optional_destruct_base<_Tp, false> {
template <class _Tp>
struct __optional_destruct_base<_Tp, true> {
typedef _Tp value_type;
+# if _LIBCPP_STD_VER >= 26
+ static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed");
+# else
+ static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed");
+# endif
static_assert(is_object_v<value_type>, "instantiation of optional with a non-object type is undefined behavior");
union {
char __null_state_;
@@ -136,7 +146,7 @@ struct __optional_destruct_base<_Tp, true> {
}
};
-template <class _Tp, bool>
+template <class _Tp>
struct __optional_storage_base : __optional_destruct_base<_Tp> {
using __base _LIBCPP_NODEBUG = __optional_destruct_base<_Tp>;
using value_type = _Tp;
@@ -174,78 +184,6 @@ struct __optional_storage_base : __optional_destruct_base<_Tp> {
__construct(std::forward<_That>(__opt).__get());
}
}
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
- __swap(__optional_storage_base& __rhs) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) {
- using std::swap;
- if (this->has_value() == __rhs.has_value()) {
- if (this->has_value())
- swap(this->__get(), __rhs.__get());
- } else {
- if (this->has_value()) {
- __rhs.__construct(std::move(this->__get()));
- this->reset();
- } else {
- this->__construct(std::move(__rhs.__get()));
- __rhs.reset();
- }
- }
- }
-
- // [optional.observe]
- _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
- return std::addressof(this->__get());
- }
-
- _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
- return std::addressof(this->__get());
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
- return this->__get();
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
- return this->__get();
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
- return std::move(this->__get());
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
- return std::move(this->__get());
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& {
- if (!this->has_value())
- std::__throw_bad_optional_access();
- return this->__get();
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
- if (!this->has_value())
- std::__throw_bad_optional_access();
- return this->__get();
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
- if (!this->has_value())
- std::__throw_bad_optional_access();
- return std::move(this->__get());
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& {
- if (!this->has_value())
- std::__throw_bad_optional_access();
- return std::move(this->__get());
- }
};
template <class _Tp, bool = is_trivially_copy_constructible_v<_Tp>>
@@ -348,68 +286,12 @@ using __optional_sfinae_assign_base_t _LIBCPP_NODEBUG =
__sfinae_assign_base< (is_copy_constructible_v<_Tp> && is_copy_assignable_v<_Tp>),
(is_move_constructible_v<_Tp> && is_move_assignable_v<_Tp>)>;
-template <class _Tp>
-struct __optional_iterator_base : __optional_move_assign_base<_Tp> {
- using __optional_move_assign_base<_Tp>::__optional_move_assign_base;
-};
-
-# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-
-template <class _Tp>
- requires is_object_v<_Tp>
-struct __optional_iterator_base<_Tp> : __optional_move_assign_base<_Tp> {
-private:
- using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
- using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>;
-
-public:
- using __optional_move_assign_base<_Tp>::__optional_move_assign_base;
-
-# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- using iterator = __bounded_iter<__pointer>;
- using const_iterator = __bounded_iter<__const_pointer>;
-# else
- using iterator = __capacity_aware_iterator<__pointer, optional<_Tp>, 1>;
- using const_iterator = __capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>;
-# endif
-
- // [optional.iterators], iterator support
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept {
- auto* __ptr = std::addressof(this->__get());
-
-# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
-# else
- return std::__make_capacity_aware_iterator<__pointer, optional<_Tp>, 1>(__ptr);
-# endif
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept {
- auto* __ptr = std::addressof(this->__get());
-
-# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
- return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
-# else
- return std::__make_capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>(__ptr);
-# endif
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept {
- return begin() + (this->has_value() ? 1 : 0);
- }
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept {
- return begin() + (this->has_value() ? 1 : 0);
- }
-};
-
-# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
-
template <class _Tp>
class _LIBCPP_DECLSPEC_EMPTY_BASES optional
- : public __optional_iterator_base<_Tp>,
+ : public __optional_move_assign_base<_Tp>,
private __optional_sfinae_ctor_base_t<_Tp>,
private __optional_sfinae_assign_base_t<_Tp> {
- using __base _LIBCPP_NODEBUG = __optional_iterator_base<_Tp>;
+ using __base _LIBCPP_NODEBUG = __optional_move_assign_base<_Tp>;
public:
using value_type = __libcpp_remove_reference_t<_Tp>;
@@ -419,11 +301,6 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
private:
static_assert(!is_same_v<remove_cv_t<_Tp>, in_place_t>, "instantiation of optional with in_place_t is ill-formed");
static_assert(!is_same_v<remove_cv_t<_Tp>, nullopt_t>, "instantiation of optional with nullopt_t is ill-formed");
-# if _LIBCPP_STD_VER >= 26
- static_assert(!is_rvalue_reference_v<_Tp>, "instantiation of optional with an rvalue reference type is ill-formed");
-# else
- static_assert(!is_reference_v<_Tp>, "instantiation of optional with a reference type is ill-formed");
-# endif
static_assert(is_destructible_v<_Tp>, "instantiation of optional with a non-destructible type is ill-formed");
static_assert(!is_array_v<_Tp>, "instantiation of optional with an array type is ill-formed");
@@ -602,17 +479,79 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
swap(optional& __opt) noexcept((is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>)) {
- this->__swap(__opt);
+ using std::swap;
+ if (this->has_value() == __opt.has_value()) {
+ if (this->has_value())
+ swap(this->__get(), __opt.__get());
+ } else {
+ if (this->has_value()) {
+ __opt.__construct(std::move(this->__get()));
+ this->reset();
+ } else {
+ this->__construct(std::move(__opt.__get()));
+ __opt.reset();
+ }
+ }
+ }
+
+ // [optional.observe]
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+ return this->__get();
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+ return this->__get();
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+ return std::move(this->__get());
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+ return std::move(this->__get());
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+ return std::addressof(this->__get());
}
- using __base::operator*;
- using __base::operator->;
+ _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+ return std::addressof(this->__get());
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& {
+ if (!this->has_value())
+ std::__throw_bad_optional_access();
+ return this->__get();
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
+ if (!this->has_value())
+ std::__throw_bad_optional_access();
+ return this->__get();
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
+ if (!this->has_value())
+ std::__throw_bad_optional_access();
+ return std::move(this->__get());
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& {
+ if (!this->has_value())
+ std::__throw_bad_optional_access();
+ return std::move(this->__get());
+ }
_LIBCPP_HIDE_FROM_ABI constexpr explicit operator bool() const noexcept { return has_value(); }
using __base::__get;
using __base::has_value;
- using __base::value;
template <class _Up = remove_cv_t<_Tp>>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
@@ -745,6 +684,51 @@ class _LIBCPP_DECLSPEC_EMPTY_BASES optional
# endif // _LIBCPP_STD_VER >= 23
using __base::reset;
+
+# if _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+
+private:
+ using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
+ using __const_pointer _LIBCPP_NODEBUG = add_pointer_t<const _Tp>;
+
+public:
+# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+ using iterator = __bounded_iter<__pointer>;
+ using const_iterator = __bounded_iter<__const_pointer>;
+# else
+ using iterator = __capacity_aware_iterator<__pointer, optional<_Tp>, 1>;
+ using const_iterator = __capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>;
+# endif
+
+ // [optional.iterators], iterator support
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator begin() noexcept {
+ auto* __ptr = std::addressof(this->__get());
+
+# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+ return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
+# else
+ return std::__make_capacity_aware_iterator<__pointer, optional<_Tp>, 1>(__ptr);
+# endif
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator begin() const noexcept {
+ auto* __ptr = std::addressof(this->__get());
+
+# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+ return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
+# else
+ return std::__make_capacity_aware_iterator<__const_pointer, optional<_Tp>, 1>(__ptr);
+# endif
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr iterator end() noexcept {
+ return begin() + (this->has_value() ? 1 : 0);
+ }
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const_iterator end() const noexcept {
+ return begin() + (this->has_value() ? 1 : 0);
+ }
+
+# endif // _LIBCPP_STD_VER >= 26 && _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
};
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__optional/optional_ref.h b/libcxx/include/__optional/optional_ref.h
index d137b3c40c7e6..9207d22f8f9b7 100644
--- a/libcxx/include/__optional/optional_ref.h
+++ b/libcxx/include/__optional/optional_ref.h
@@ -49,17 +49,17 @@
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
-#if _LIBCPP_STD_VER >= 17
+#if _LIBCPP_STD_VER >= 26
_LIBCPP_BEGIN_NAMESPACE_STD
template <class _Tp>
-struct __optional_storage_base<_Tp, true> {
+struct __optional_ref_base {
using value_type = _Tp;
using __raw_type _LIBCPP_NODEBUG = remove_reference_t<_Tp>;
__raw_type* __value_;
- _LIBCPP_HIDE_FROM_ABI constexpr __optional_storage_base() noexcept : __value_(nullptr) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr __optional_ref_base() noexcept : __value_(nullptr) {}
template <class _Up>
_LIBCPP_HIDE_FROM_ABI constexpr void __convert_init_ref_val(_Up&& __val) {
@@ -68,7 +68,7 @@ struct __optional_storage_base<_Tp, true> {
}
template <class _UArg>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_storage_base(in_place_t, _UArg&& __uarg) {
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_ref_base(in_place_t, _UArg&& __uarg) {
static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>,
"Attempted to construct a reference element in optional from a "
"possible temporary");
@@ -77,20 +77,20 @@ struct __optional_storage_base<_Tp, true> {
# if _LIBCPP_STD_VER >= 23
template <class _Fp, class... _Args>
- constexpr __optional_storage_base(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) {
+ constexpr __optional_ref_base(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) {
__convert_init_ref_val(std::forward<invoke_result_t<_Fp, _Args...>>(
std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)));
}
# endif
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void reset() noexcept { __value_ = nullptr; }
+ _LIBCPP_HIDE_FROM_ABI constexpr void reset() noexcept { __value_ = nullptr; }
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool has_value() const noexcept { return __value_ != nullptr; }
_LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const noexcept { return *__value_; }
template <class _UArg>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) {
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct(_UArg&& __val) {
static_assert(!__reference_constructs_from_temporary_v<_Tp, _UArg>,
"Attempted to construct a reference element in tuple from a "
"possible temporary");
@@ -98,83 +98,44 @@ struct __optional_storage_base<_Tp, true> {
}
template <class _That>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct_from(_That&& __opt) {
+ _LIBCPP_HIDE_FROM_ABI constexpr void __construct_from(_That&& __opt) {
if (__opt.has_value())
__construct(std::forward<_That>(__opt).__get());
}
-
- template <class _That>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __assign_from(_That&& __opt) {
- if (has_value() == __opt.has_value()) {
- if (has_value())
- *__value_ = std::forward<_That>(__opt).__get();
- } else {
- if (has_value())
- reset();
- else
- __construct(std::forward<_That>(__opt).__get());
- }
- }
-
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __swap(__optional_storage_base& __rhs) noexcept {
- std::swap(__value_, __rhs.__value_);
- }
-
- // [optional.ref.observe]
- _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
- return std::addressof(this->__get());
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept {
- _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
- return this->__get();
- }
-
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const {
- if (!this->has_value())
- std::__throw_bad_optional_access();
- return this->__get();
- }
};
-# if _LIBCPP_STD_VER >= 26
-
template <class _Tp>
-struct __optional_iterator_base;
-
-template <class _Tp>
-struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> {
- using __optional_storage_base<_Tp&>::__optional_storage_base;
+struct __optional_ref_iterator_base : __optional_ref_base<_Tp&> {
+ using __optional_ref_base<_Tp&>::__optional_ref_base;
};
-# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
+# if _LIBCPP_HAS_EXPERIMENTAL_OPTIONAL_ITERATOR
template <class _Tp>
requires(is_object_v<_Tp> && !__is_unbounded_array_v<_Tp>)
-struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> {
+struct __optional_ref_iterator_base<_Tp&> : __optional_ref_base<_Tp&> {
private:
using __pointer _LIBCPP_NODEBUG = add_pointer_t<_Tp>;
public:
- using __optional_storage_base<_Tp&>::__optional_storage_base;
+ using __optional_ref_base<_Tp&>::__optional_ref_base;
-# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
using iterator = __bounded_iter<__pointer>;
-# else
+# else
using iterator = __capacity_aware_iterator<__pointer, optional<_Tp&>, 1>;
-# endif
+# endif
// [optional.ref.iterators], iterator support
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const noexcept {
auto* __ptr = this->has_value() ? std::addressof(this->__get()) : nullptr;
-# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
+# ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_OPTIONAL
return std::__make_bounded_iter(__ptr, __ptr, __ptr + (this->has_value() ? 1 : 0));
-# else
+# else
return std::__make_capacity_aware_iterator<__pointer, optional<_Tp&>, 1>(__ptr);
-# endif
+# endif
}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto end() const noexcept {
@@ -182,11 +143,11 @@ struct __optional_iterator_base<_Tp&> : __optional_storage_base<_Tp&> {
}
};
-# endif
+# endif
template <class _Tp>
-class optional<_Tp&> : public __optional_iterator_base<_Tp&> {
- using __base _LIBCPP_NODEBUG = __optional_iterator_base<_Tp&>;
+class optional<_Tp&> : public __optional_ref_iterator_base<_Tp&> {
+ using __base _LIBCPP_NODEBUG = __optional_ref_iterator_base<_Tp&>;
template <class _Up, class _QualUp>
static constexpr bool __check_optionalU_ctor =
@@ -291,15 +252,28 @@ class optional<_Tp&> : public __optional_iterator_base<_Tp&> {
return this->__get();
}
- constexpr void swap(optional& __rhs) noexcept { this->__swap(__rhs); }
+ constexpr void swap(optional& __rhs) noexcept { std::swap(this->__value_, __rhs.__value_); }
- using __base::operator->;
- using __base::operator*;
+ // [optional.ref.observe]
+ _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator-> called on a disengaged value");
+ return std::addressof(this->__get());
+ }
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() const noexcept {
+ _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
+ return this->__get();
+ }
constexpr explicit operator bool() const noexcept { return has_value(); }
using __base::has_value;
- using __base::value;
+
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() const {
+ if (!this->has_value())
+ std::__throw_bad_optional_access();
+ return this->__get();
+ }
template <class _Up = remove_cv_t<_Tp>>
requires(!is_array_v<_Tp> && is_object_v<_Tp>)
@@ -346,11 +320,9 @@ class optional<_Tp&> : public __optional_iterator_base<_Tp&> {
using __base::reset;
};
-# endif // _LIBCPP_STD_VER >= 26
-
_LIBCPP_END_NAMESPACE_STD
-#endif // _LIBCPP_STD_VER >= 17
+#endif // _LIBCPP_STD_VER >= 26
_LIBCPP_POP_MACROS
More information about the libcxx-commits
mailing list