[libcxx-commits] [libcxx] [libc++] Refactor optional constructors to use conditional explicit (PR #152999)
Nikolas Klauser via libcxx-commits
libcxx-commits at lists.llvm.org
Thu Feb 19 05:11:45 PST 2026
https://github.com/philnik777 updated https://github.com/llvm/llvm-project/pull/152999
>From c1160d202c57bdf8d471c55cd654e0fc2c4a2d18 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Thu, 19 Feb 2026 14:11:09 +0100
Subject: [PATCH] Stuff
---
libcxx/include/__tuple/sfinae_helpers.h | 20 ---
libcxx/include/optional | 176 ++++++++----------------
2 files changed, 58 insertions(+), 138 deletions(-)
diff --git a/libcxx/include/__tuple/sfinae_helpers.h b/libcxx/include/__tuple/sfinae_helpers.h
index f81048f4062bd..f96268b3bbbf0 100644
--- a/libcxx/include/__tuple/sfinae_helpers.h
+++ b/libcxx/include/__tuple/sfinae_helpers.h
@@ -17,26 +17,6 @@
_LIBCPP_BEGIN_NAMESPACE_STD
-#ifndef _LIBCPP_CXX03_LANG
-
-struct __check_tuple_constructor_fail {
- static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_explicit_default() { return false; }
- static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit_default() { return false; }
- template <class...>
- static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_explicit() {
- return false;
- }
- template <class...>
- static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_implicit() {
- return false;
- }
- template <class...>
- static _LIBCPP_HIDE_FROM_ABI constexpr bool __enable_assign() {
- return false;
- }
-};
-#endif // !defined(_LIBCPP_CXX03_LANG)
-
#if _LIBCPP_STD_VER >= 17
template <bool _CanCopy, bool _CanMove>
diff --git a/libcxx/include/optional b/libcxx/include/optional
index b851a858ed26a..a89c72b1cae76 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -830,70 +830,41 @@ private:
is_lvalue_reference_v<_Tp> && reference_constructs_from_temporary_v<_Tp, _Up>;
# endif
- // LWG2756: conditionally explicit conversion from _Up
- struct _CheckOptionalArgsConstructor {
- template <class _Up>
- _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() {
- return is_constructible_v<_Tp, _Up&&> && is_convertible_v<_Up&&, _Tp>;
- }
-
- template <class _Up>
- _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() {
- return is_constructible_v<_Tp, _Up&&> && !is_convertible_v<_Up&&, _Tp>;
- }
- };
- template <class _Up>
- using _CheckOptionalArgsCtor _LIBCPP_NODEBUG =
- _If< _IsNotSame<__remove_cvref_t<_Up>, in_place_t>::value && _IsNotSame<__remove_cvref_t<_Up>, optional>::value &&
- (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_optional<__remove_cvref_t<_Up>>::value),
- _CheckOptionalArgsConstructor,
- __check_tuple_constructor_fail >;
- template <class _QualUp>
- struct _CheckOptionalLikeConstructor {
- template <class _Up, class _Opt = optional<_Up>>
- using __check_constructible_from_opt _LIBCPP_NODEBUG =
- _Or< is_constructible<_Tp, _Opt&>,
- is_constructible<_Tp, _Opt const&>,
- is_constructible<_Tp, _Opt&&>,
- is_constructible<_Tp, _Opt const&&>,
- is_convertible<_Opt&, _Tp>,
- is_convertible<_Opt const&, _Tp>,
- is_convertible<_Opt&&, _Tp>,
- is_convertible<_Opt const&&, _Tp> >;
- template <class _Up, class _Opt = optional<_Up>>
- using __check_assignable_from_opt _LIBCPP_NODEBUG =
- _Or< is_assignable<_Tp&, _Opt&>,
- is_assignable<_Tp&, _Opt const&>,
- is_assignable<_Tp&, _Opt&&>,
- is_assignable<_Tp&, _Opt const&&> >;
- template <class _Up, class _QUp = _QualUp>
- _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_implicit() {
- return is_convertible<_QUp, _Tp>::value &&
- (is_same_v<remove_cv_t<_Tp>, bool> || !__check_constructible_from_opt<_Up>::value);
- }
- template <class _Up, class _QUp = _QualUp>
- _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_explicit() {
- return !is_convertible<_QUp, _Tp>::value &&
- (is_same_v<remove_cv_t<_Tp>, bool> || !__check_constructible_from_opt<_Up>::value);
- }
- template <class _Up, class _QUp = _QualUp>
- _LIBCPP_HIDE_FROM_ABI static constexpr bool __enable_assign() {
- // Construction and assignability of _QUp to _Tp has already been
- // checked.
- return !__check_constructible_from_opt<_Up>::value && !__check_assignable_from_opt<_Up>::value;
- }
- };
+ template <class _Up, class _UnqualUp = __remove_cvref_t<_Up>>
+ static constexpr bool __enable_conversion_ctor =
+ !is_same_v<_UnqualUp, in_place_t> && !is_same_v<_UnqualUp, optional> &&
+ (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_optional<_UnqualUp>::value);
+
+ template <class _Up, class _Opt = optional<_Up>>
+ using __check_constructible_from_opt _LIBCPP_NODEBUG =
+ _Or<is_constructible<_Tp, _Opt&>,
+ is_constructible<_Tp, _Opt const&>,
+ is_constructible<_Tp, _Opt&&>,
+ is_constructible<_Tp, _Opt const&&>,
+ is_convertible<_Opt&, _Tp>,
+ is_convertible<_Opt const&, _Tp>,
+ is_convertible<_Opt&&, _Tp>,
+ is_convertible<_Opt const&&, _Tp>>;
+
+ template <class _Up, class _Opt = optional<_Up>>
+ using __check_assignable_from_opt _LIBCPP_NODEBUG =
+ _Or<is_assignable<_Tp&, _Opt&>,
+ is_assignable<_Tp&, _Opt const&>,
+ is_assignable<_Tp&, _Opt&&>,
+ is_assignable<_Tp&, _Opt const&&> >;
template <class _Up, class _QualUp>
- using _CheckOptionalLikeCtor _LIBCPP_NODEBUG =
- _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp> >::value,
- _CheckOptionalLikeConstructor<_QualUp>,
- __check_tuple_constructor_fail >;
+ static constexpr bool __enable_optional_like_ctor =
+ _And<_IsNotSame<_Up, _Tp>,
+ is_constructible<_Tp, _QualUp>,
+ _Or<is_same<remove_cv_t<_Tp>, bool>, _Not<__check_constructible_from_opt<_Up>>>>::value;
+
template <class _Up, class _QualUp>
- using _CheckOptionalLikeAssign _LIBCPP_NODEBUG =
- _If< _And< _IsNotSame<_Up, _Tp>, is_constructible<_Tp, _QualUp>, is_assignable<_Tp&, _QualUp> >::value,
- _CheckOptionalLikeConstructor<_QualUp>,
- __check_tuple_constructor_fail >;
+ static constexpr bool __enable_optional_like_assign =
+ _And<_IsNotSame<_Up, _Tp>,
+ is_constructible<_Tp, _QualUp>,
+ _Not<__check_constructible_from_opt<_Up>>,
+ _Not<__check_assignable_from_opt<_Up>>>::value;
public:
_LIBCPP_HIDE_FROM_ABI constexpr optional() noexcept {}
@@ -914,71 +885,57 @@ public:
_LIBCPP_HIDE_FROM_ABI constexpr explicit optional(in_place_t, initializer_list<_Up> __il, _Args&&... __args)
: __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)
+ template <class _Up = remove_cv_t<_Tp>,
+ enable_if_t<__enable_conversion_ctor<_Up> && is_constructible_v<_Tp, _Up&&>, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI explicit(!is_convertible_v<_Up&&, _Tp>) 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)
# 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<__enable_conversion_ctor<_Up> && is_constructible_v<_Tp, _Up&&>, int> = 0>
+ requires __libcpp_opt_ref_ctor_deleted<_Up>
+ optional(_Up&&) = delete;
+# endif // _LIBCPP_STD_VER >= 26
// 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)
+ template <class _Up, enable_if_t<__enable_optional_like_ctor<_Up, const _Up&>, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v<const _Up&, _Tp>) 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)
+
# 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<__enable_optional_like_ctor<_Up, const _Up&>, int> = 0>
+ requires __libcpp_opt_ref_ctor_deleted<_Up>
+ optional(const optional<_Up>&) = delete;
+# endif // _LIBCPP_STD_VER >= 26
// 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)
+ template <class _Up, enable_if_t<__enable_optional_like_ctor<_Up, _Up&&>, int> = 0>
+ _LIBCPP_HIDE_FROM_ABI
+ _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v<_Up&&, _Tp>) 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)
# 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<__enable_optional_like_ctor<_Up, _Up&&>, int> = 0>
+ requires __libcpp_opt_ref_ctor_deleted<_Up>
+ optional(optional<_Up>&&) = delete;
+# endif // _LIBCPP_STD_VER >= 26
// deleted optional<T&> constructors and additional optional<T&> constructors
# if _LIBCPP_STD_VER >= 26
- // 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;
-
- template <class _Up = remove_cv_t<_Tp>,
- enable_if_t<_CheckOptionalArgsCtor<_Up>::template __enable_explicit<_Up>(), int> = 0>
- 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_same_v<remove_cvref_t<_Tp>, optional<_Up>>) &&
@@ -993,24 +950,6 @@ public:
(!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;
-
- template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up const&>::template __enable_explicit<_Up>(), int> = 0>
- 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;
-
- 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_same_v<remove_cvref_t<_Tp>, optional<_Up>>) &&
@@ -1060,14 +999,15 @@ public:
}
// LWG2756
- template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::template __enable_assign<_Up>(), int> = 0>
+ template <class _Up,
+ enable_if_t<__enable_optional_like_assign<_Up, const _Up&> && is_assignable_v<_Tp&, const _Up&>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(const optional<_Up>& __v) {
this->__assign_from(__v);
return *this;
}
// LWG2756
- template <class _Up, enable_if_t<_CheckOptionalLikeCtor<_Up, _Up&&>::template __enable_assign<_Up>(), int> = 0>
+ template <class _Up, enable_if_t<__enable_optional_like_assign<_Up, _Up&&>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 optional& operator=(optional<_Up>&& __v) {
this->__assign_from(std::move(__v));
return *this;
More information about the libcxx-commits
mailing list