[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