[libcxx-commits] [libcxx] [libc++] Refactor optional constructors to use conditional explicit (PR #152999)

Nikolas Klauser via libcxx-commits libcxx-commits at lists.llvm.org
Mon Aug 11 05:28:16 PDT 2025


https://github.com/philnik777 created https://github.com/llvm/llvm-project/pull/152999

None

>From 7239fa10ccffa3c3dfd52091175cd3274341bc07 Mon Sep 17 00:00:00 2001
From: Nikolas Klauser <nikolasklauser at berlin.de>
Date: Mon, 11 Aug 2025 14:27:56 +0200
Subject: [PATCH] [libc++] Refactor optional constructors to use conditional
 explicit

---
 libcxx/include/__tuple/sfinae_helpers.h |  20 ----
 libcxx/include/optional                 | 125 +++++++++---------------
 2 files changed, 44 insertions(+), 101 deletions(-)

diff --git a/libcxx/include/__tuple/sfinae_helpers.h b/libcxx/include/__tuple/sfinae_helpers.h
index f314381d0a48d..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 _LIBCPP_EXPORTED_FROM_ABI __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 e81bff50daad6..e78bdb104d79f 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -604,69 +604,20 @@ private:
   static_assert(!is_array_v<value_type>, "instantiation of optional with an array type is ill-formed");
 
   // 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 _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&&>>;
 
-  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 >;
-  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 >;
+  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&&>>;
 
 public:
   _LIBCPP_HIDE_FROM_ABI constexpr optional() noexcept {}
@@ -686,30 +637,34 @@ 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                                                                        = value_type,
-            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)) {}
-
-  template <class _Up, 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)) {}
+  template <class _Up,
+            class _DependentU = enable_if_t<
+                !is_same_v<__remove_cvref_t<_Up>, in_place_t> && !is_same_v<__remove_cvref_t<_Up>, optional> &&
+                    (!is_same_v<remove_cv_t<_Tp>, bool> || !__is_std_optional<__remove_cvref_t<_Up>>::value),
+                _Up>,
+            enable_if_t<is_constructible_v<_Tp, _DependentU>, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit(!is_convertible_v<_Up&&, _Tp>) optional(_Up&& __v)
+      : __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) {
-    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) {
+  template <class _Up,
+            class _DependentU = enable_if_t<!is_same_v<_Up, _Tp>, _Up>,
+            enable_if_t<is_constructible_v<_Tp, const _DependentU&> &&
+                            (is_same_v<remove_cv_t<_Tp>, bool> || !__check_constructible_from_opt<_DependentU>::value),
+                        int>  = 0>
+  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v<const _Up&, _Tp>) optional(const optional<_Up>& __v) {
     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) {
-    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) {
+  template <class _Up,
+            class _DependentU = enable_if_t<!is_same_v<_Up, _Tp>, _Up>,
+            enable_if_t<is_constructible_v<_Tp, _DependentU&&> &&
+                            (is_same_v<remove_cv_t<_Tp>, bool> || !__check_constructible_from_opt<_DependentU>::value),
+                        int>  = 0>
+  _LIBCPP_HIDE_FROM_ABI
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 explicit(!is_convertible_v<_Up&&, _Tp>) optional(optional<_Up>&& __v) {
     this->__construct_from(std::move(__v));
   }
 
@@ -746,14 +701,22 @@ public:
   }
 
   // LWG2756
-  template <class _Up, enable_if_t<_CheckOptionalLikeAssign<_Up, _Up const&>::template __enable_assign<_Up>(), int> = 0>
+  template <class _Up,
+            class _DependentU = enable_if_t<!is_same_v<_Tp, _Up>, _Up>,
+            enable_if_t<is_constructible_v<_Tp, const _DependentU&> && is_assignable_v<_Tp&, const _DependentU&> &&
+                            !__check_constructible_from_opt<_Up>::value && !__check_assignable_from_opt<_Up>::value,
+                        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,
+            class _DependentU = enable_if_t<!is_same_v<_Tp, _Up>, _Up>,
+            enable_if_t<is_constructible_v<_Tp, _DependentU&&> && is_assignable_v<_Tp&, _DependentU&&> &&
+                            !__check_constructible_from_opt<_Up>::value && !__check_assignable_from_opt<_Up>::value,
+                        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