Skip to content

[libc++] Implement the <type_traits> parts of P1317R2 #151480

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

frederick-vs-ja
Copy link
Contributor

@frederick-vs-ja frederick-vs-ja commented Jul 31, 2025

Changes of std::apply are still blocked on related changes in P2165R4. Towards #148183.

@frederick-vs-ja frederick-vs-ja requested a review from a team as a code owner July 31, 2025 09:29
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Jul 31, 2025
@frederick-vs-ja frederick-vs-ja added c++26 libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. and removed libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. labels Jul 31, 2025
@llvmbot
Copy link
Member

llvmbot commented Jul 31, 2025

@llvm/pr-subscribers-libcxx

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

Changes

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 --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]

Copy link

github-actions bot commented Jul 31, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@frederick-vs-ja frederick-vs-ja force-pushed the p1317r2-type-traits branch 3 times, most recently from 926656e to 3f8ae7d Compare July 31, 2025 11:00
Comment on lines 14 to 22
#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/invoke.h>
#include <__type_traits/remove_reference.h>
#include <__utility/declval.h>
#include <__utility/integer_sequence.h>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These includes seemingly heavily break module builds. I guess we need to expand the std_core module a lot.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a bit problematic. I almost wonder if we should put this new stuff under __tuple instead? It clearly belongs to type_traits, but putting it inside __tuple would simplify things from a modularization perspective.

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

@ldionne ldionne left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have some minor comments, this basically looks good but I have some maintainability concerns with the current tests!

Comment on lines 14 to 22
#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/invoke.h>
#include <__type_traits/remove_reference.h>
#include <__utility/declval.h>
#include <__utility/integer_sequence.h>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a bit problematic. I almost wonder if we should put this new stuff under __tuple instead? It clearly belongs to type_traits, but putting it inside __tuple would simplify things from a modularization perspective.

}

void test_valid() {
// test array
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like a lot of these tests are generated? Would there be a way to share this between the three test files we're adding in this patch, since there seems to be a lot of redundancy? I'm a bit worried about the maintainability of these tests as written right now (but am quite happy about their apparent exhaustiveness).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++26 libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants