[libcxx-commits] [libcxx] [libc++] Correct `optional<T&>` implementation (PR #174537)
via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Jan 5 22:50:44 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-libcxx
Author: William Tran-Viet (smallp-o-p)
<details>
<summary>Changes</summary>
Resolves #<!-- -->174350
- Several issues were found in the current implementation of `optional<T&>`
- `value()`, `operator*()`, `and_then()`, `transform()`, `operator->()` still provided their ref-qualified versions for rvalues and `const&`.
- Using the listed methods on an rvalue `optional<T&>` would cause a compile failure due to a mismatch in return types.
- On the latter, `operator*`, `operator->` would return `const` for a `optional<T&>`, which is an incorrect deep const.
- Also corrects the behavior of `value_or` which should return `remove_cv_t<T>` (in our case `decay_t<_Tp>`)
- Add several test cases to verify behavior, update `value_or` tests
---
Patch is 61.98 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/174537.diff
28 Files Affected:
- (modified) libcxx/include/optional (+230-47)
- (modified) libcxx/test/libcxx/utilities/optional/optional.object/optional.object.observe/value_or.compile.pass.cpp (+2-2)
- (modified) libcxx/test/std/utilities/optional/optional.monadic/and_then.pass.cpp (+15-12)
- (modified) libcxx/test/std/utilities/optional/optional.monadic/or_else.pass.cpp (+17)
- (modified) libcxx/test/std/utilities/optional/optional.monadic/transform.pass.cpp (+8-6)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.assign/assign_value.pass.cpp (+21-5)
- (added) libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.compile.fail.cpp (+26)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp (+1)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.assign/nullopt_t.pass.cpp (+11)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/U.pass.cpp (+40-1)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/const_optional_U.pass.cpp (+48)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/in_place_t.pass.cpp (+19-2)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/move.pass.cpp (+20-12)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/optional_U.pass.cpp (+52)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/ref_constructs_from_temporary.verify.cpp (+22-13)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.mod/reset.pass.cpp (+1)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/bool.pass.cpp (+32-2)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference.pass.cpp (+35-2)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const.pass.cpp (+51-30)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_const_rvalue.pass.cpp (+41-2)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/dereference_rvalue.pass.cpp (+41-2)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/has_value.pass.cpp (+6-2)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow.pass.cpp (+5-2)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/op_arrow_const.pass.cpp (+5-2)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const.pass.cpp (+41-3)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_const_rvalue.pass.cpp (+41-3)
- (modified) libcxx/test/std/utilities/optional/optional.object/optional.object.observe/value_or.pass.cpp (+3-1)
- (modified) libcxx/test/support/copy_move_types.h (+4-1)
``````````diff
diff --git a/libcxx/include/optional b/libcxx/include/optional
index 568c86556d156..487cfa1e7ce6e 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -510,8 +510,6 @@ struct __optional_storage_base<_Tp, true> {
_LIBCPP_HIDE_FROM_ABI constexpr value_type& __get() const& noexcept { return *__value_; }
- _LIBCPP_HIDE_FROM_ABI constexpr value_type&& __get() const&& noexcept { return std::forward<value_type>(*__value_); }
-
template <class _UArg>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void __construct(_UArg&& __val) {
_LIBCPP_ASSERT_INTERNAL(!has_value(), "__construct called for engaged __optional_storage");
@@ -909,38 +907,61 @@ public:
: __base(in_place, __il, std::forward<_Args>(__args)...) {}
template <class _Up = _Tp, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr optional(_Up&& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>)
+# endif
+ : __base(in_place, std::forward<_Up>(__v)) {
+ }
template <class _Up = remove_cv_t<_Tp>,
enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v) : __base(in_place, std::forward<_Up>(__v)) {}
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Up&& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>)
+# endif
+ : __base(in_place, std::forward<_Up>(__v)) {
+ }
// LWG2756: conditionally explicit conversion from const optional<_Up>&
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>)
+# endif
+ {
this->__construct_from(__v);
}
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_explicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(const optional<_Up>& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up&>)
+# endif
+ {
this->__construct_from(__v);
}
// LWG2756: conditionally explicit conversion from optional<_Up>&&
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_implicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(optional<_Up>&& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>)
+# endif
+ {
this->__construct_from(std::move(__v));
}
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_explicit<_Up>(), int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit optional(optional<_Up>&& __v)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp&, _Up>)
+# endif
+ {
this->__construct_from(std::move(__v));
}
- // deleted optional<T&> constructors
+ // deleted optional<T&> constructors and additional optional<T&> constructors
# if _LIBCPP_STD_VER >= 26
- template <class _Up, class... _Args, enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>, int> = 0>
- requires __libcpp_opt_ref_ctor_deleted<_Up>
- explicit optional(in_place_t, initializer_list<_Up>, _Args&&...) = delete;
-
+ // optional(U&&)
template <class _Up = _Tp, enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_implicit<_Up>(), int> = 0>
requires __libcpp_opt_ref_ctor_deleted<_Up>
optional(_Up&&) = delete;
@@ -950,6 +971,21 @@ public:
requires __libcpp_opt_ref_ctor_deleted<_Up>
explicit optional(_Up&&) = delete;
+ // optional(optional<U>& rhs)
+ template <class _Up>
+ requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!__is_std_optional<remove_cvref_t<_Tp>>::value) &&
+ (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&>
+ constexpr explicit(!is_convertible_v<_Up&, _Tp&>)
+ optional(optional<_Up>& __rhs) noexcept(is_nothrow_constructible_v<_Tp&, _Up&>) {
+ this->__construct_from(__rhs);
+ }
+
+ template <class _Up>
+ requires __libcpp_opt_ref_ctor_deleted<_Up> && (!__is_std_optional<remove_cvref_t<_Tp>>::value) &&
+ (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up&>
+ constexpr explicit optional(optional<_Up>& __rhs) noexcept = delete;
+
+ // optional(const optional<U>&)
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_implicit<_Up>(), int> = 0>
requires __libcpp_opt_ref_ctor_deleted<_Up>
optional(const optional<_Up>&) = delete;
@@ -958,6 +994,7 @@ public:
requires __libcpp_opt_ref_ctor_deleted<_Up>
explicit optional(const optional<_Up>&) = delete;
+ // optional(optional<U>&&)
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_implicit<_Up>(), int> = 0>
requires __libcpp_opt_ref_ctor_deleted<_Up>
optional(optional<_Up>&&) = delete;
@@ -965,6 +1002,20 @@ public:
template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_explicit<_Up>(), int> = 0>
requires __libcpp_opt_ref_ctor_deleted<_Up>
explicit optional(optional<_Up>&&) = delete;
+
+ // optional(const optional<U>&&)
+ template <class _Up>
+ requires(!__libcpp_opt_ref_ctor_deleted<_Up>) && (!__is_std_optional<remove_cvref_t<_Tp>>::value) &&
+ (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v<const _Up, _Tp&>)
+ optional(const optional<_Up>&& __v) noexcept(is_nothrow_constructible_v<_Tp&, const _Up>) {
+ this->__construct_from(std::move(__v));
+ }
+
+ template <class _Up>
+ requires __libcpp_opt_ref_ctor_deleted<_Up> && (!__is_std_optional<remove_cvref_t<_Tp>>::value) &&
+ (!is_same_v<_Tp&, _Up>) && is_constructible_v<_Tp&, _Up>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional(const optional<_Up>&& __v) noexcept = delete;
# endif
# if _LIBCPP_STD_VER >= 23
@@ -1013,8 +1064,12 @@ public:
return *this;
}
- template <class... _Args, enable_if_t<is_constructible_v<_Tp, _Args...>, int> = 0>
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args) {
+ template <class... _Args, enable_if_t<__is_constructible_for_optional_v<_Tp, _Args...>, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(_Args&&... __args)
+# if _LIBCPP_STD_VER >= 26
+ noexcept(is_lvalue_reference_v<_Tp> && is_nothrow_constructible_v<_Tp, _Args...>)
+# endif
+ {
reset();
this->__construct(std::forward<_Args>(__args)...);
return this->__get();
@@ -1022,20 +1077,19 @@ public:
template <class _Up,
class... _Args,
- enable_if_t<is_constructible_v<_Tp, initializer_list<_Up>&, _Args...>
-# if _LIBCPP_STD_VER >= 26
- && !reference_constructs_from_temporary_v<_Tp&, _Up>
-# endif
- ,
- int> = 0>
+ enable_if_t<__is_constructible_for_optional_initializer_list_v<_Tp, _Up, _Args...>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp& emplace(initializer_list<_Up> __il, _Args&&... __args) {
reset();
this->__construct(__il, std::forward<_Args>(__args)...);
return this->__get();
}
- _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void
- swap(optional& __opt) noexcept(is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>) {
+ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void swap(optional& __opt) noexcept(
+ (is_nothrow_move_constructible_v<_Tp> && is_nothrow_swappable_v<_Tp>)
+# if _LIBCPP_STD_VER >= 26
+ || is_lvalue_reference_v<_Tp>
+# endif
+ ) {
if (this->has_value() == __opt.has_value()) {
if (this->has_value())
this->__swap(__opt);
@@ -1050,32 +1104,56 @@ public:
}
}
- _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept {
+ _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp const> operator->() const noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
_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_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
_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 {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp& operator*() const& noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
_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 {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& operator*() & noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
_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 {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& operator*() && noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
_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 {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr const _Tp&& operator*() const&& noexcept
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
_LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(this->has_value(), "optional operator* called on a disengaged value");
return std::move(this->__get());
}
@@ -1085,25 +1163,41 @@ public:
using __base::__get;
using __base::has_value;
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const& {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const& value() const&
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
if (!this->has_value())
std::__throw_bad_optional_access();
return this->__get();
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() & {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp& value() &
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
if (!this->has_value())
std::__throw_bad_optional_access();
return this->__get();
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() && {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp&& value() &&
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
if (!this->has_value())
std::__throw_bad_optional_access();
return std::move(this->__get());
}
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&& {
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp const&& value() const&&
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
+ {
if (!this->has_value())
std::__throw_bad_optional_access();
return std::move(this->__get());
@@ -1111,8 +1205,7 @@ public:
template <class _Up = remove_cv_t<_Tp>>
# if _LIBCPP_STD_VER >= 26
- requires(!(is_lvalue_reference_v<_Tp> && is_function_v<__libcpp_remove_reference_t<_Tp>>) &&
- !(is_lvalue_reference_v<_Tp> && is_array_v<__libcpp_remove_reference_t<_Tp>>))
+ requires(!is_lvalue_reference_v<_Tp>)
# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) const& {
static_assert(is_copy_constructible_v<_Tp>, "optional<T>::value_or: T must be copy constructible");
@@ -1130,19 +1223,11 @@ public:
return this->has_value() ? std::move(this->__get()) : static_cast<_Tp>(std::forward<_Up>(__v));
}
-# if _LIBCPP_STD_VER >= 26
- template <class _Up = remove_cv_t<_Tp>>
- requires(is_lvalue_reference_v<_Tp> &&
- !(is_function_v<__libcpp_remove_reference_t<_Tp>> || is_array_v<__libcpp_remove_reference_t<_Tp>>))
- [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr _Tp value_or(_Up&& __v) && {
- static_assert(is_move_constructible_v<_Tp>, "optional<T>::value_or: T must be move constructible");
- static_assert(is_convertible_v<_Up, _Tp>, "optional<T>::value_or: U must be convertible to T");
- return this->has_value() ? this->__get() : static_cast<_Tp>(std::forward<_Up>(__v));
- }
-# endif
-
# if _LIBCPP_STD_VER >= 23
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) & {
using _Up = invoke_result_t<_Func, _Tp&>;
static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
@@ -1153,6 +1238,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const& {
using _Up = invoke_result_t<_Func, const _Tp&>;
static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
@@ -1163,6 +1251,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) && {
using _Up = invoke_result_t<_Func, _Tp&&>;
static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
@@ -1173,6 +1264,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const&& {
using _Up = invoke_result_t<_Func, const _Tp&&>;
static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
@@ -1183,6 +1277,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) & {
using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&>>;
static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
@@ -1195,6 +1292,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const& {
using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&>>;
static_assert(!is_array_v<_Up>, "Result of f(value()) should not be an Array");
@@ -1207,6 +1307,9 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) && {
using _Up = remove_cv_t<invoke_result_t<_Func, _Tp&&>>;
static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array");
@@ -1219,8 +1322,11 @@ public:
}
template <class _Func>
+# if _LIBCPP_STD_VER >= 26
+ requires(!is_lvalue_reference_v<_Tp>)
+# endif
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto transform(_Func&& __f) const&& {
- using _Up = remove_cvref_t<invoke_result_t<_Func, const _Tp&&>>;
+ using _Up = remove_cv_t<invoke_result_t<_Func, const _Tp&&>>;
static_assert(!is_array_v<_Up>, "Result of f(std::move(value())) should not be an Array");
static_assert(!is_same_v<_Up, in_place_t>, "Result of f(std::move(value())) should not be std::in_place_t");
static_assert(!is_same_v<_Up, nullopt_t>, "Result of f(std::move(value())) should not be std::nullopt_t");
@@ -1233,6 +1339,9 @@ public:
template <invocable _Func>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) const&
requires is_copy_constructible_v<_Tp>
+# if _LIBCPP_STD_VER >= 26
+ && (!is_lvalue_reference_v<_Tp>)
+# endif
{
static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
"Result of f() should be the same type as this optional");
@@ -1244,6 +1353,9 @@ public:
template <invocable _Func>
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr optional or_else(_Func&& __f) &&
requires is_move_constructible_v<_Tp>
+# if _LIBCPP_STD_VER >= 26
+ && (!is_lvalue_reference_v<_Tp>)
+# endif
{
static_assert(is_same_v<remove_cvref_t<invoke_result_t<_Func>>, optional>,
"Result of f() should be the same type as this optional");
@@ -1254,6 +1366,77 @@ public:
# endif // _LIBCPP_STD_VER >= 23
using __base::reset;
+
+// optional<T&> overloads
+# if _LIBCPP_STD_VER >= 26
+
+ _LIBCPP_HIDE_FROM_ABI constexpr add_pointer_t<_Tp> operator->() const noexcept
+ requires(is_lvalue_reference_v<_Tp>)
+ {
+ _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
+ requires(is_lvalue_reference_v<_Tp>)
+ {
+ _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
+ requires(is_lvalue_reference_v<_Tp>)
+ {
+ if (!this->has_value())
+ std::__throw_bad_optional_access();
+ return this->__get();
+ }
+
+ template <class _Up = remove_cvref_t<_Tp>>
+ requires(is_lvalue_reference_v<_Tp> && is_object_v<__libcpp_remove_reference_t<_Tp>> &&
+ !is_array_v<__libcpp_remove_reference_t<_Tp>>)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr decay_t<_Tp> value_or(_Up&& __v) const {
+ using _X = remove_cvref_t<_Tp>;
+ static_assert(is_constructible_v<_X, _Tp&>, "optional<T&>::value_or: remove_cv_t<T> must be constructible");
+ static_assert(is_convertible_v<_Up, _X>, "optional<T&>::value_or: U must be convertible to remove_cv_t<T>");
+ return this->has_value() ? this->__get() : static_cast<_X>(std::forward<_Up>(__v));
+ }
+
+ template <class _Func>
+ requires(is_lvalue_reference_v<_Tp>)
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto and_then(_Func&& __f) const {
+ using _Up = invoke_result_t<_Func, _Tp&>;
+ static_assert(__is_std_optional<remove_cvref_t<_Up>>::value,
+ "Result of f(value()) must be a specialization of std::optional");
+ if (*this)
+ return std::invoke(std::forward<_Func>(__f), value());
+ return remove_cvref_t<_Up>();
+ }
+
+ template <class _Func>
+ requires(is_lvalue_reference_v<_Tp...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/174537
More information about the libcxx-commits
mailing list