[libcxx-commits] [libcxx] [libc++] P2255R2: Add deleted tuple constructor overloads (PR #205379)

Yihan Wang via libcxx-commits libcxx-commits at lists.llvm.org
Sat Aug 15 02:12:12 PDT 2026


================
@@ -614,21 +614,77 @@ public:
       : _And<_Not<_IsThisTuple<_Up...> >, // extension to allow mis-behaved user constructors
              is_constructible<_Tp, _Up>... > {};
 
-  template <class... _Up,
-            __enable_if_t< _And< _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, _EnableUTypesCtor<_Up...> >::value,
-                           int> = 0>
+  template <class... _Up>
+  struct _EnableUTypesCtorBase : _And<_BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, _EnableUTypesCtor<_Up...> > {};
+
+  template <bool, class... _Up>
+  struct _EnableUTypesCtorNoDangling : false_type {};
+
+#    if _LIBCPP_STD_VER >= 23
+  template <class... _Up>
+  static constexpr bool __has_danglings() {
+    if constexpr (sizeof...(_Up) == sizeof...(_Tp))
+      return (__reference_constructs_from_temporary_v<_Tp, _Up&&> || ...);
+    else
+      return false;
+  }
+
+  template <class _Source, class _DecayedSource = __remove_cvref_t<_Source> >
+  static constexpr bool __has_danglings_from_tuple_like = false;
+
+  template <class _Source, class... _Up>
+  static constexpr bool __has_danglings_from_tuple_like<_Source, tuple<_Up...> > =
+      __has_danglings<__copy_cvref_t<_Source, _Up>...>();
+
+  template <class _Source, class _U1, class _U2>
+  static constexpr bool __has_danglings_from_tuple_like<_Source, pair<_U1, _U2> > =
+      __has_danglings<__copy_cvref_t<_Source, _U1>, __copy_cvref_t<_Source, _U2> >();
+
+  template <bool __dangles, class _CtorEnabled>
+  static constexpr bool __check_danglings_from_constructor = false;
+
+  template <class _CtorEnabled>
+  static constexpr bool __check_danglings_from_constructor<true, _CtorEnabled> = _CtorEnabled::value;
+
+  template <bool __dangles, class _CtorEnabled>
+  static constexpr bool __check_no_danglings_from_constructor = _CtorEnabled::value;
+
+  template <class _CtorEnabled>
+  static constexpr bool __check_no_danglings_from_constructor<true, _CtorEnabled> = false;
+
+  template <class... _Up>
+  static constexpr bool __has_danglings_from_utypes =
+      __check_danglings_from_constructor<__has_danglings<_Up...>(), _EnableUTypesCtorBase<_Up...> >;
+
+  template <class... _Up>
+  static constexpr bool __has_no_danglings_from_utypes =
+      __check_no_danglings_from_constructor<__has_danglings<_Up...>(), _EnableUTypesCtorBase<_Up...> >;
+#   else
+  template <class... _Up>
+  static constexpr bool __has_no_danglings_from_utypes = _EnableUTypesCtorBase<_Up...>::value;
+#    endif // _LIBCPP_STD_VER >= 23
+
+  template <class... _Up, __enable_if_t< __has_no_danglings_from_utypes<_Up...>, int> = 0>
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 explicit(!_And<is_convertible<_Up, _Tp>...>::value)
       tuple(_Up&&... __u) noexcept(_And<is_nothrow_constructible<_Tp, _Up>...>::value)
       : __base_(__forward_args{}, std::forward<_Up>(__u)...) {}
 
-  template <class _Alloc,
-            class... _Up,
-            __enable_if_t< _And< _BoolConstant<sizeof...(_Up) == sizeof...(_Tp)>, _EnableUTypesCtor<_Up...> >::value,
-                           int> = 0>
+  template <class _Alloc, class... _Up, __enable_if_t< __has_no_danglings_from_utypes<_Up...>, int> = 0>
----------------
yronglin wrote:

The existing overload is constrained with enable_if, which does not participate in constraint subsumption. Therefore the deleted overload’s requires clause does not make it more constrained than the existing overload, and leaving both enabled makes overload resolution ambiguous.  Eg. https://godbolt.org/z/15PhvzzYx.

https://github.com/llvm/llvm-project/pull/205379


More information about the libcxx-commits mailing list