[libcxx-commits] [libcxx] [libc++] Implement the `<type_traits>` parts of P1317R2 (PR #151480)

via libcxx-commits libcxx-commits at lists.llvm.org
Thu Jul 31 02:30:03 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-libcxx

Author: A. Jiang (frederick-vs-ja)

<details>
<summary>Changes</summary>

Changes of `std::apply` are still blocked on related changes in P2165R4.

---

Patch is 136.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/151480.diff


12 Files Affected:

- (modified) libcxx/docs/ReleaseNotes/22.rst (+2) 
- (modified) libcxx/docs/Status/Cxx2cPapers.csv (+1-1) 
- (modified) libcxx/include/CMakeLists.txt (+1) 
- (added) libcxx/include/__type_traits/is_applicable.h (+105) 
- (modified) libcxx/include/module.modulemap.in (+4) 
- (modified) libcxx/include/type_traits (+16) 
- (modified) libcxx/modules/std/type_traits.inc (+18) 
- (modified) libcxx/test/libcxx/type_traits/no_specializations.verify.cpp (+8-1) 
- (modified) libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp (+2) 
- (added) libcxx/test/std/utilities/meta/meta.rel/is_applicable.compile.pass.cpp (+598) 
- (added) libcxx/test/std/utilities/meta/meta.rel/is_nothrow_applicable.compile.pass.cpp (+654) 
- (added) libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/apply_result.compile.pass.cpp (+629) 


``````````diff
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 15bf46d44b07f..05c375359a688 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -38,6 +38,8 @@ What's New in Libc++ 22.0.0?
 Implemented Papers
 ------------------
 
+- P1317R2: Remove return type deduction in ``std::apply`` (`Github <https://github.com/llvm/llvm-project/issues/148183>`__)
+  (Only components in ``<type_traits>`` are implemented.)
 - P2321R2: ``zip`` (`Github <https://github.com/llvm/llvm-project/issues/105169>`__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release)
 
 Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index febb0c176f9c4..99be92021434e 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -155,5 +155,5 @@
 "`P2781R9 <https://wg21.link/P2781R9>`__","``std::constant_wrapper``","2025-06 (Sofia)","","",""
 "`P3697R1 <https://wg21.link/P3697R1>`__","Minor additions to C++26 standard library hardening","2025-06 (Sofia)","","",""
 "`P3552R3 <https://wg21.link/P3552R3>`__","Add a Coroutine Task Type","2025-06 (Sofia)","","",""
-"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","","",""
+"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","|In Progress|","",""
 "","","","","",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 51444ec668e2b..a823a2f3a7a50 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -819,6 +819,7 @@ set(files
   __type_traits/is_aggregate.h
   __type_traits/is_allocator.h
   __type_traits/is_always_bitcastable.h
+  __type_traits/is_applicable.h
   __type_traits/is_arithmetic.h
   __type_traits/is_array.h
   __type_traits/is_assignable.h
diff --git a/libcxx/include/__type_traits/is_applicable.h b/libcxx/include/__type_traits/is_applicable.h
new file mode 100644
index 0000000000000..fc97a0c4a9ad1
--- /dev/null
+++ b/libcxx/include/__type_traits/is_applicable.h
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
+#define _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__functional/invoke.h>
+#include <__fwd/get.h>
+#include <__tuple/tuple_like.h>
+#include <__tuple/tuple_size.h>
+#include <__type_traits/conjunction.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/remove_reference.h>
+#include <__utility/declval.h>
+#include <__utility/integer_sequence.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#  pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+template <class _Fn, class _Tuple>
+struct __apply_result_disabled_base {};
+
+template <class _Fn, class _Tuple, class _Tp>
+struct __apply_result_enabled_base {
+  using type _LIBCPP_NODEBUG = _Tp;
+};
+
+template <bool _Applicable, bool _Nothrow, class _Tp>
+struct __applicability_traits {
+  static constexpr bool __applicable         = true;
+  static constexpr bool __nothrow_applicable = _Nothrow;
+
+  template <class _Fn, class _Tuple>
+  using __base_type _LIBCPP_NODEBUG = __apply_result_enabled_base<_Fn, _Tuple, _Tp>;
+};
+
+template <bool _Nothrow, class _Tp>
+struct __applicability_traits<false, _Nothrow, _Tp> {
+  static_assert(!_Nothrow, "misspecified [_Applicable = false, _Nothrow = true]");
+  static constexpr bool __applicable         = false;
+  static constexpr bool __nothrow_applicable = false;
+
+  template <class _Fn, class _Tuple>
+  using __base_type _LIBCPP_NODEBUG = __apply_result_disabled_base<_Fn, _Tuple>;
+};
+
+template <class _Fn, class _Tuple>
+consteval auto __applicability_traits_of() {
+  if constexpr (__tuple_like<_Tuple>)
+    return []<size_t... _Is>(index_sequence<_Is...>) {
+      constexpr bool __is_tuple_applicable = requires(_Fn&& __fn, _Tuple&& __tuple) {
+        std::invoke(static_cast<_Fn&&>(__fn), std::get<_Is>(static_cast<_Tuple&&>(__tuple))...);
+      };
+      if constexpr (__is_tuple_applicable)
+        return __applicability_traits<
+            true,
+            noexcept(std::invoke(std::declval<_Fn>(), std::get<_Is>(std::declval<_Tuple>())...)),
+            decltype(std::invoke(std::declval<_Fn>(), std::get<_Is>(std::declval<_Tuple>())...))>{};
+      else
+        return __applicability_traits<false, false, void>{};
+    }(make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{});
+  else
+    return __applicability_traits<false, false, void>{};
+}
+
+template <class _Fn, class _Tuple>
+struct _LIBCPP_NO_SPECIALIZATIONS is_applicable
+    : bool_constant<decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__applicable> {};
+
+template <class _Fn, class _Tuple>
+struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_applicable
+    : bool_constant<decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__nothrow_applicable> {};
+
+template <class _Fn, class _Tuple>
+_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_applicable_v =
+    decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__applicable;
+
+template <class _Fn, class _Tuple>
+_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_applicable_v =
+    decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__nothrow_applicable;
+
+template <class _Fn, class _Tuple>
+struct _LIBCPP_NO_SPECIALIZATIONS apply_result
+    : decltype(std::__applicability_traits_of<_Fn, _Tuple>())::template __base_type<_Fn, _Tuple> {};
+
+template <class _Fn, class _Tuple>
+using apply_result_t = apply_result<_Fn, _Tuple>::type;
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 5857a83b5fe14..6766960144a83 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -112,6 +112,10 @@ module std_core [system] {
       header "__type_traits/is_always_bitcastable.h"
       export std_core.type_traits.integral_constant
     }
+    module is_applicable {
+      header "__type_traits/is_applicable.h"
+      export std_core.type_traits.integral_constant
+    }
     module is_arithmetic {
       header "__type_traits/is_arithmetic.h"
       export std_core.type_traits.integral_constant
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index a6e0c1867566b..f8c3f744e07f4 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -168,6 +168,10 @@ namespace std
     template <class R, class Fn, class... ArgTypes>
       struct is_nothrow_invocable_r;                            // since C++17
 
+    template<class Fn, class Tuple> struct is_applicable;       // since C++26
+    template<class Fn, class Tuple>
+      struct is_nothrow_applicable;                             // since C++26
+
     // Alignment properties and transformations:
     template <class T> struct alignment_of;
     template <size_t Len, size_t Align = most_stringent_alignment_requirement>
@@ -183,6 +187,7 @@ namespace std
       struct result_of<Fn(ArgTypes...)>;                        // deprecated in C++17; removed in C++20
     template <class Fn, class... ArgTypes>
       struct invoke_result;                                     // since C++17
+    template<class Fn, class Tuple> struct apply_result;        // since C++26
 
     // const-volatile modifications:
     template <class T>
@@ -265,6 +270,9 @@ namespace std
     template <class Fn, class... ArgTypes>
       using invoke_result_t
        = typename invoke_result<Fn, ArgTypes...>::type;         // since C++17
+    template <class Fn, class... ArgTypes>
+      using apply_result_t
+       = typename invoke_result<Fn, ArgTypes...>::type;         // since C++26
 
     template <class...>
       using void_t = void;                                      // since C++17
@@ -442,6 +450,10 @@ namespace std
         = is_nothrow_invocable<Fn, ArgTypes...>::value;         // since C++17
       template <class R, class Fn, class... ArgTypes> inline constexpr bool is_nothrow_invocable_r_v
         = is_nothrow_invocable_r<R, Fn, ArgTypes...>::value;    // since C++17
+      template<class Fn, class Tuple> constexpr bool is_applicable_v
+        = is_applicable<Fn, Tuple>::value;                      // since C++26
+      template<class Fn, class Tuple> constexpr bool is_nothrow_applicable_v
+        = is_nothrow_applicable<Fn, Tuple>::value;              // since C++26
 
       // [meta.logical], logical operator traits:
       template<class... B> struct conjunction;                  // since C++17
@@ -559,6 +571,10 @@ namespace std
 #    include <__type_traits/reference_converts_from_temporary.h>
 #  endif
 
+#  if _LIBCPP_STD_VER >= 26
+#    include <__type_traits/is_applicable.h>
+#  endif
+
 #  include <version>
 
 #  if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/modules/std/type_traits.inc b/libcxx/modules/std/type_traits.inc
index 6823c86ed153b..0ad2bb4bea27f 100644
--- a/libcxx/modules/std/type_traits.inc
+++ b/libcxx/modules/std/type_traits.inc
@@ -121,6 +121,9 @@ export namespace std {
   using std::rank;
 
   // [meta.rel], type relations
+#if _LIBCPP_STD_VER >= 26
+  using std::is_applicable;
+#endif
   using std::is_base_of;
 #if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_virtual_base_of)
   using std::is_virtual_base_of;
@@ -134,6 +137,9 @@ export namespace std {
   using std::is_invocable;
   using std::is_invocable_r;
 
+#if _LIBCPP_STD_VER >= 26
+  using std::is_nothrow_applicable;
+#endif
   using std::is_nothrow_invocable;
   using std::is_nothrow_invocable_r;
 
@@ -183,6 +189,9 @@ export namespace std {
   using std::remove_pointer_t;
 
   // [meta.trans.other], other transformations
+#if _LIBCPP_STD_VER >= 26
+  using std::apply_result;
+#endif
   using std::basic_common_reference;
   using std::common_reference;
   using std::common_type;
@@ -196,6 +205,9 @@ export namespace std {
   using std::unwrap_ref_decay;
   using std::unwrap_reference;
 
+#if _LIBCPP_STD_VER >= 26
+  using std::apply_result_t;
+#endif
   using std::common_reference_t;
   using std::common_type_t;
   using std::conditional_t;
@@ -305,6 +317,9 @@ export namespace std {
   using std::rank_v;
 
   // [meta.rel], type relations
+#if _LIBCPP_STD_VER >= 26
+  using std::is_applicable_v;
+#endif
   using std::is_base_of_v;
 #if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_virtual_base_of)
   using std::is_virtual_base_of_v;
@@ -313,6 +328,9 @@ export namespace std {
   using std::is_invocable_r_v;
   using std::is_invocable_v;
   // using std::is_layout_compatible_v;
+#if _LIBCPP_STD_VER >= 26
+  using std::is_nothrow_applicable_v;
+#endif
   using std::is_nothrow_convertible_v;
   using std::is_nothrow_invocable_r_v;
   using std::is_nothrow_invocable_v;
diff --git a/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp b/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
index 897ae89365014..b76a75a3b1584 100644
--- a/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
+++ b/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
@@ -53,6 +53,11 @@ SPECIALIZE_TRAIT(unwrap_reference); // expected-error {{cannot be specialized}}
 SPECIALIZE_TRAIT(unwrap_ref_decay); // expected-error {{cannot be specialized}}
 #  endif
 
+#  if TEST_STD_VER >= 26
+template <>
+struct std::apply_result<S, S>; // expected-error {{cannot be specialized}}
+#  endif
+
 #  undef SPECIALIZE_TRAIT
 #  define SPECIALIZE_UTT(Trait)                                                                                        \
     template <>                                                                                                        \
@@ -165,7 +170,9 @@ SPECIALIZE_BTT(reference_converts_from_temporary); // expected-error 2 {{cannot
 #  endif
 
 #  if TEST_STD_VER >= 26
-SPECIALIZE_BTT(is_virtual_base_of); // expected-error 2 {{cannot be specialized}}
+SPECIALIZE_BTT(is_applicable);         // expected-error 2 {{cannot be specialized}}
+SPECIALIZE_BTT(is_nothrow_applicable); // expected-error 2 {{cannot be specialized}}
+SPECIALIZE_BTT(is_virtual_base_of);    // expected-error 2 {{cannot be specialized}}
 #  endif
 
 #  undef SPECIALIZE_UTT
diff --git a/libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp b/libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp
index 3db7a214b27bd..eb021f5840c6c 100644
--- a/libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp
+++ b/libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp
@@ -113,4 +113,6 @@ static_assert(std::is_base_of<std::false_type, std::is_scoped_enum<int>>::value,
 #  if defined(__cpp_lib_is_virtual_base_of) && __cpp_lib_is_virtual_base_of >= 202406L
 static_assert(std::is_base_of<std::false_type, std::is_virtual_base_of<int, int>>::value, "");
 #  endif
+static_assert(std::is_base_of<std::false_type, std::is_applicable<int, int>>::value, "");
+static_assert(std::is_base_of<std::false_type, std::is_nothrow_applicable<int, int>>::value, "");
 #endif
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_applicable.compile.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_applicable.compile.pass.cpp
new file mode 100644
index 0000000000000..bd8531c02a2e0
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.rel/is_applicable.compile.pass.cpp
@@ -0,0 +1,598 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <type_traits>
+
+// template<class Fn, class Tuple> struct is_applicable;
+
+// template<class Fn, class Tuple>
+// constexpr bool is_applicable_v = is_applicable<T, U>::value;
+
+#include <cassert>
+#include <cstddef>
+#include <array>
+#include <complex>
+#include <ranges>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "callable_types.h"
+#include "test_iterators.h"
+
+struct empty_aggregate {};
+
+struct derived_from_tuple_int : std::tuple<int> {};
+
+template <>
+struct std::tuple_size<derived_from_tuple_int> : std::integral_constant<std::size_t, 1> {};
+
+template <std::size_t I>
+  requires(I < 1)
+struct std::tuple_element<I, derived_from_tuple_int> {
+  using type = std::tuple_element_t<I, std::tuple<int>>;
+};
+
+template <class Fn, class Tuple, bool Expected>
+void test_is_applicable() {
+  static_assert(std::is_applicable<Fn, Tuple>::value == Expected);
+  static_assert(std::is_applicable_v<Fn, Tuple> == Expected);
+
+  static_assert(std::is_base_of_v<std::bool_constant<Expected>, std::is_applicable<Fn, Tuple>>);
+  static_assert(std::is_convertible_v<std::is_applicable<Fn, Tuple>*, std::bool_constant<Expected>*>);
+}
+
+template <class Func, class Tuple, bool Expected>
+void test_is_applicable_from_function() {
+  static_assert(std::is_function_v<Func>);
+
+  test_is_applicable<Func, Tuple, Expected>();
+  test_is_applicable<Func&, Tuple, Expected>();
+
+  test_is_applicable<Func*, Tuple, Expected>();
+  test_is_applicable<Func*&, Tuple, Expected>();
+  test_is_applicable<Func* const, Tuple, Expected>();
+  test_is_applicable<Func* const&, Tuple, Expected>();
+  test_is_applicable<Func* volatile, Tuple, Expected>();
+  test_is_applicable<Func* volatile&, Tuple, Expected>();
+  test_is_applicable<Func* const volatile, Tuple, Expected>();
+  test_is_applicable<Func* const volatile&, Tuple, Expected>();
+}
+
+void test_valid() {
+  // test array
+  test_is_applicable_from_function<int(), std::array<int, 0>, true>();
+  test_is_applicable_from_function<int(), std::array<long, 0>&, true>();
+  test_is_applicable_from_function<int(), const std::array<char, 0>, true>();
+  test_is_applicable_from_function<int(), const std::array<std::array<int, 1>, 0>&, true>();
+  test_is_applicable_from_function<int() noexcept, std::array<int, 0>, true>();
+  test_is_applicable_from_function<int() noexcept, std::array<long, 0>&, true>();
+  test_is_applicable_from_function<int() noexcept, const std::array<char, 0>, true>();
+  test_is_applicable_from_function<int() noexcept, const std::array<std::array<int, 1>, 0>&, true>();
+
+  test_is_applicable_from_function<int(long), std::array<int, 1>, true>();
+  test_is_applicable_from_function<int&(int), std::array<long, 1>&, true>();
+  test_is_applicable_from_function<const int && (float), const std::array<double, 1>, true>();
+  test_is_applicable_from_function<void(double), const std::array<char, 1>&, true>();
+  test_is_applicable_from_function<int(long) noexcept, std::array<int, 1>, true>();
+  test_is_applicable_from_function<int&(int) noexcept, std::array<long, 1>&, true>();
+  test_is_applicable_from_function<const int && (float) noexcept, const std::array<double, 1>, true>();
+  test_is_applicable_from_function<void(double) noexcept, const std::array<char, 1>&, true>();
+
+  test_is_applicable_from_function<int(long, int), std::array<int, 2>, true>();
+  test_is_applicable_from_function<int&(long, int), std::array<int, 2>&, true>();
+  test_is_applicable_from_function<const int && (long, int), const std::array<int, 2>, true>();
+  test_is_applicable_from_function<void(long, int), const std::array<int, 2>&, true>();
+  test_is_applicable_from_function<int(long, int) noexcept, std::array<int, 2>, true>();
+  test_is_applicable_from_function<int&(long, int) noexcept, std::array<int, 2>&, true>();
+  test_is_applicable_from_function<const int && (long, int) noexcept, const std::array<int, 2>, true>();
+  test_is_applicable_from_function<void(long, int) noexcept, const std::array<int, 2>&, true>();
+
+  test_is_applicable<ConstCallable<bool>, std::array<int, 0>, true>();
+  test_is_applicable<ConstCallable<bool>, std::array<int, 1>&, true>();
+  test_is_applicable<ConstCallable<bool>, const std::array<int, 2>, true>();
+  test_is_applicable<ConstCallable<bool>, const std::array<int, 3>&, true>();
+
+  test_is_applicable<NoExceptCallable<bool>, std::array<int, 0>, true>();
+  test_is_applicable<NoExceptCallable<bool>, std::array<int, 1>&, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::array<int, 2>, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::array<int, 3>&, true>();
+
+  // test complex
+  test_is_applicable_from_function<float(float, float), std::complex<float>, true>();
+  test_is_applicable_from_function<float(float&, float&), std::complex<float>&, true>();
+  test_is_applicable_from_function<void(float, float), const std::complex<float>, true>();
+  test_is_applicable_from_function<double(float, float), const std::complex<float>&, true>();
+  test_is_applicable_from_function<float(float, float) noexcept, std::complex<float>, true>();
+  test_is_applicable_from_function<float(float&, float&) noexcept, std::complex<float>&, true>();
+  test_is_applicable_from_function<void(float, float) noexcept, const std::complex<float>, true>();
+  test_is_applicable_from_function<double(float, float) noexcept, const std::complex<float>&, true>();
+
+  test_is_applicable<ConstCallable<bool>, std::complex<float>, true>();
+  test_is_applicable<ConstCallable<bool>, std::complex<float>&, true>();
+  test_is_applicable<ConstCallable<bool>, const std::complex<float>, true>();
+  test_is_applicable<ConstCallable<bool>, const std::complex<float>&, true>();
+
+  test_is_applicable<NoExceptCallable<bool>, std::complex<float>, true>();
+  test_is_applicable<NoExceptCallable<bool>, std::complex<float>&, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::complex<float>, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::complex<float>&, true...
[truncated]

``````````

</details>


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


More information about the libcxx-commits mailing list