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

A. Jiang via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 5 06:55:02 PDT 2025


https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/151480

>From 6cf03e7ba074fb6eb2f7ee556ac0e130bddcc52c Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Thu, 31 Jul 2025 17:26:24 +0800
Subject: [PATCH 1/3] [libc++] Implement the `<type_traits>` parts of P1317R2

Changes of `std::apply` are still blocked on related changes in P2165R4.
---
 libcxx/docs/ReleaseNotes/22.rst               |   2 +
 libcxx/docs/Status/Cxx2cPapers.csv            |   2 +-
 libcxx/include/CMakeLists.txt                 |   1 +
 libcxx/include/__type_traits/is_applicable.h  | 115 +++
 libcxx/include/module.modulemap.in            |   4 +
 libcxx/include/type_traits                    |  16 +
 libcxx/modules/std/type_traits.inc            |  18 +
 .../type_traits/no_specializations.verify.cpp |   9 +-
 ...ed_from_integral_constant.compile.pass.cpp |   2 +
 .../meta.rel/is_applicable.compile.pass.cpp   | 598 ++++++++++++++++
 .../is_nothrow_applicable.compile.pass.cpp    | 652 ++++++++++++++++++
 .../apply_result.compile.pass.cpp             | 629 +++++++++++++++++
 12 files changed, 2046 insertions(+), 2 deletions(-)
 create mode 100644 libcxx/include/__type_traits/is_applicable.h
 create mode 100644 libcxx/test/std/utilities/meta/meta.rel/is_applicable.compile.pass.cpp
 create mode 100644 libcxx/test/std/utilities/meta/meta.rel/is_nothrow_applicable.compile.pass.cpp
 create mode 100644 libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/apply_result.compile.pass.cpp

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..00db70ac072b2
--- /dev/null
+++ b/libcxx/include/__type_traits/is_applicable.h
@@ -0,0 +1,115 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 <__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>
+
+#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, size_t... _Is>
+concept __tuple_applicable_impl = requires(_Tuple&& __tuple) {
+  [](auto&&...) {}(std::get<_Is>(static_cast<_Tuple &&>(__tuple))...);
+} && __is_invocable_v<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>;
+
+template <class _Fn, class _Tuple, size_t... _Is>
+concept __tuple_nothrow_applicable_impl = requires(_Tuple&& __tuple) {
+  {
+    [](auto&&...) noexcept {}(std::get<_Is>(static_cast<_Tuple &&>(__tuple))...)
+  } noexcept;
+} && __is_nothrow_invocable_v<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>;
+
+template <class _Fn, class _Tuple>
+consteval auto __applicability_traits_of() {
+  if constexpr (__tuple_like<_Tuple>)
+    return []<size_t... _Is>(index_sequence<_Is...>) {
+      if constexpr (__tuple_applicable_impl<_Fn, _Tuple, _Is...>) {
+        return __applicability_traits<
+            true,
+            __tuple_nothrow_applicable_impl<_Fn, _Tuple, _Is...>,
+            // FIXME: Use __invoke_result_y after merging  https://github.com/llvm/llvm-project/pull/151028.
+            typename __invoke_result<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>::type>{};
+      } 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..7f70f19044d0f
--- /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>();
+
+  test_is_applicable_from_function<double(double, double), std::complex<double>, true>();
+  test_is_applicable_from_function<double&(double&, double&), std::complex<double>&, true>();
+  test_is_applicable_from_function<void(double, double), const std::complex<double>, true>();
+  test_is_applicable_from_function<double(double, double), const std::complex<double>&, true>();
+  test_is_applicable_from_function<double(double, double) noexcept, std::complex<double>, true>();
+  test_is_applicable_from_function<double&(double&, double&) noexcept, std::complex<double>&, true>();
+  test_is_applicable_from_function<void(double, double) noexcept, const std::complex<double>, true>();
+  test_is_applicable_from_function<double(double, double) noexcept, const std::complex<double>&, true>();
+
+  test_is_applicable<ConstCallable<bool>, std::complex<double>, true>();
+  test_is_applicable<ConstCallable<bool>, std::complex<double>&, true>();
+  test_is_applicable<ConstCallable<bool>, const std::complex<double>, true>();
+  test_is_applicable<ConstCallable<bool>, const std::complex<double>&, true>();
+
+  test_is_applicable<NoExceptCallable<bool>, std::complex<double>, true>();
+  test_is_applicable<NoExceptCallable<bool>, std::complex<double>&, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::complex<double>, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::complex<double>&, true>();
+
+  test_is_applicable_from_function<long double(long double, long double), std::complex<long double>, true>();
+  test_is_applicable_from_function<long double&(long double&, long double&), std::complex<long double>&, true>();
+  test_is_applicable_from_function<void(long double, long double), const std::complex<long double>, true>();
+  test_is_applicable_from_function<double(long double, long double), const std::complex<long double>&, true>();
+  test_is_applicable_from_function<long double(long double, long double) noexcept, std::complex<long double>, true>();
+  test_is_applicable_from_function<long double&(long double&, long double&) noexcept,
+                                   std::complex<long double>&,
+                                   true>();
+  test_is_applicable_from_function<void(long double, long double) noexcept, const std::complex<long double>, true>();
+  test_is_applicable_from_function<double(long double, long double) noexcept, const std::complex<long double>&, true>();
+
+  test_is_applicable<ConstCallable<bool>, std::complex<long double>, true>();
+  test_is_applicable<ConstCallable<bool>, std::complex<long double>&, true>();
+  test_is_applicable<ConstCallable<bool>, const std::complex<long double>, true>();
+  test_is_applicable<ConstCallable<bool>, const std::complex<long double>&, true>();
+
+  test_is_applicable<NoExceptCallable<bool>, std::complex<long double>, true>();
+  test_is_applicable<NoExceptCallable<bool>, std::complex<long double>&, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::complex<long double>, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::complex<long double>&, true>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+
+  test_is_applicable_from_function<void(int*, int*), copyable_subrange, true>();
+  test_is_applicable_from_function<long(int*, int*), copyable_subrange&, true>();
+  test_is_applicable_from_function<int*&(int*, int*), const copyable_subrange, true>();
+  test_is_applicable_from_function<int* && (int*, int*), const copyable_subrange&, true>();
+  test_is_applicable_from_function<void(int*, int*) noexcept, copyable_subrange, true>();
+  test_is_applicable_from_function<long(int*, int*) noexcept, copyable_subrange&, true>();
+  test_is_applicable_from_function<int*&(int*, int*) noexcept, const copyable_subrange, true>();
+  test_is_applicable_from_function<int* && (int*, int*) noexcept, const copyable_subrange&, true>();
+
+  test_is_applicable<ConstCallable<bool>, copyable_subrange, true>();
+  test_is_applicable<ConstCallable<bool>, copyable_subrange&, true>();
+  test_is_applicable<ConstCallable<bool>, const copyable_subrange, true>();
+  test_is_applicable<ConstCallable<bool>, const copyable_subrange&, true>();
+
+  test_is_applicable<NoExceptCallable<bool>, copyable_subrange, true>();
+  test_is_applicable<NoExceptCallable<bool>, copyable_subrange&, true>();
+  test_is_applicable<NoExceptCallable<bool>, const copyable_subrange, true>();
+  test_is_applicable<NoExceptCallable<bool>, const copyable_subrange&, true>();
+
+  using move_only_counted_iter = std::counted_iterator<cpp20_input_iterator<int*>>;
+  using move_only_subrange     = std::ranges::subrange<move_only_counted_iter, std::default_sentinel_t>;
+
+  test_is_applicable_from_function<void(move_only_counted_iter&&, std::default_sentinel_t), move_only_subrange, true>();
+  test_is_applicable_from_function<void(move_only_counted_iter&&, std::default_sentinel_t) noexcept,
+                                   move_only_subrange,
+                                   true>();
+
+  test_is_applicable<ConstCallable<bool>, move_only_subrange, true >();
+
+  test_is_applicable<NoExceptCallable<bool>, move_only_subrange, true>();
+
+  // test tuple
+  test_is_applicable_from_function<int(), std::tuple<>, true>();
+  test_is_applicable_from_function<char&(), std::tuple<>&, true>();
+  test_is_applicable_from_function<long && (), const std::tuple<>, true>();
+  test_is_applicable_from_function<void(), const std::tuple<>&, true>();
+  test_is_applicable_from_function<int() noexcept, std::tuple<>, true>();
+  test_is_applicable_from_function<char&() noexcept, std::tuple<>&, true>();
+  test_is_applicable_from_function<long && () noexcept, const std::tuple<>, true>();
+  test_is_applicable_from_function<void() noexcept, const std::tuple<>&, true>();
+
+  test_is_applicable_from_function<int(long, int), std::tuple<int, long>, true>();
+  test_is_applicable_from_function<int&(long, int), std::tuple<int, long>&, true>();
+  test_is_applicable_from_function<const int && (long, int), const std::tuple<int, long>, true>();
+  test_is_applicable_from_function<void(long, int), const std::tuple<int, long>&, true>();
+  test_is_applicable_from_function<int(long, int) noexcept, std::tuple<int, long>, true>();
+  test_is_applicable_from_function<int&(long, int) noexcept, std::tuple<int, long>&, true>();
+  test_is_applicable_from_function<const int && (long, int) noexcept, const std::tuple<int, long>, true>();
+  test_is_applicable_from_function<void(long, int) noexcept, const std::tuple<int, long>&, true>();
+
+  test_is_applicable<ConstCallable<bool>, std::tuple<>, true>();
+  test_is_applicable<ConstCallable<bool>, std::tuple<long>&, true>();
+  test_is_applicable<ConstCallable<bool>, const std::tuple<int, long>, true>();
+  test_is_applicable<ConstCallable<bool>, const std::tuple<int, double, long>&, true>();
+
+  test_is_applicable<NoExceptCallable<bool>, std::tuple<>, true>();
+  test_is_applicable<NoExceptCallable<bool>, std::tuple<long>&, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::tuple<int, long>, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::tuple<int, double, long>&, true>();
+
+  // test pair
+  test_is_applicable_from_function<int(long, int), std::pair<int, long>, true>();
+  test_is_applicable_from_function<int&(long, int), std::pair<int, long>&, true>();
+  test_is_applicable_from_function<const int && (long, int), const std::pair<int, long>, true>();
+  test_is_applicable_from_function<void(long, int), const std::pair<int, long>&, true>();
+  test_is_applicable_from_function<int(long, int) noexcept, std::pair<int, long>, true>();
+  test_is_applicable_from_function<int&(long, int) noexcept, std::pair<int, long>&, true>();
+  test_is_applicable_from_function<const int && (long, int) noexcept, const std::pair<int, long>, true>();
+  test_is_applicable_from_function<void(long, int) noexcept, const std::pair<int, long>&, true>();
+
+  test_is_applicable<ConstCallable<bool>, std::pair<char, wchar_t>, true>();
+  test_is_applicable<ConstCallable<bool>, std::pair<float, long>&, true>();
+  test_is_applicable<ConstCallable<bool>, const std::pair<int, long>, true>();
+  test_is_applicable<ConstCallable<bool>, const std::pair<int, double>&, true>();
+
+  test_is_applicable<NoExceptCallable<bool>, std::pair<char, wchar_t>, true>();
+  test_is_applicable<NoExceptCallable<bool>, std::pair<float, long>&, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::pair<int, long>, true>();
+  test_is_applicable<NoExceptCallable<bool>, const std::pair<int, double>&, true>();
+}
+
+void test_volatile() {
+  // test array
+  test_is_applicable_from_function<void(int), volatile std::array<int, 1>, false>();
+  test_is_applicable_from_function<void(int), volatile std::array<int, 1>&, false>();
+  test_is_applicable_from_function<void(int), const volatile std::array<int, 1>, false>();
+  test_is_applicable_from_function<void(int), const volatile std::array<int, 1>&, false>();
+  test_is_applicable_from_function<void(int) noexcept, volatile std::array<int, 1>, false>();
+  test_is_applicable_from_function<void(int) noexcept, volatile std::array<int, 1>&, false>();
+  test_is_applicable_from_function<void(int) noexcept, const volatile std::array<int, 1>, false>();
+  test_is_applicable_from_function<void(int) noexcept, const volatile std::array<int, 1>&, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, volatile std::array<int, 1>, false>();
+  test_is_applicable<NoExceptCallable<bool>, volatile std::array<int, 1>&, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile std::array<int, 1>, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile std::array<int, 1>&, false>();
+
+  // test complex
+  test_is_applicable_from_function<void(double, double), volatile std::complex<double>, false>();
+  test_is_applicable_from_function<void(double, double), volatile std::complex<double>&, false>();
+  test_is_applicable_from_function<void(double, double), const volatile std::complex<double>, false>();
+  test_is_applicable_from_function<void(double, double), const volatile std::complex<double>&, false>();
+  test_is_applicable_from_function<void(double, double) noexcept, volatile std::complex<double>, false>();
+  test_is_applicable_from_function<void(double, double) noexcept, volatile std::complex<double>&, false>();
+  test_is_applicable_from_function<void(double, double) noexcept, const volatile std::complex<double>, false>();
+  test_is_applicable_from_function<void(double, double) noexcept, const volatile std::complex<double>&, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, volatile std::complex<double>, false>();
+  test_is_applicable<NoExceptCallable<bool>, volatile std::complex<double>&, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile std::complex<double>, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile std::complex<double>&, false>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+
+  test_is_applicable_from_function<void(int*, int*), volatile copyable_subrange, false>();
+  test_is_applicable_from_function<void(int*, int*), volatile copyable_subrange&, false>();
+  test_is_applicable_from_function<void(int*, int*), const volatile copyable_subrange, false>();
+  test_is_applicable_from_function<void(int*, int*), const volatile copyable_subrange&, false>();
+  test_is_applicable_from_function<void(int*, int*) noexcept, volatile copyable_subrange, false>();
+  test_is_applicable_from_function<void(int*, int*) noexcept, volatile copyable_subrange&, false>();
+  test_is_applicable_from_function<void(int*, int*) noexcept, const volatile copyable_subrange, false>();
+  test_is_applicable_from_function<void(int*, int*) noexcept, const volatile copyable_subrange&, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, volatile copyable_subrange, false>();
+  test_is_applicable<NoExceptCallable<bool>, volatile copyable_subrange&, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile copyable_subrange, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile copyable_subrange&, false>();
+
+  // test tuple
+  test_is_applicable_from_function<void(int, char*, double), volatile std::tuple<int, char*, double>, false>();
+  test_is_applicable_from_function<void(int, char*, double), volatile std::tuple<int, char*, double>&, false>();
+  test_is_applicable_from_function<void(int, char*, double), const volatile std::tuple<int, char*, double>, false>();
+  test_is_applicable_from_function<void(int, char*, double), const volatile std::tuple<int, char*, double>&, false>();
+  test_is_applicable_from_function<void(int, char*, double) noexcept, volatile std::tuple<int, char*, double>, false>();
+  test_is_applicable_from_function<void(int, char*, double) noexcept,
+                                   volatile std::tuple<int, char*, double>&,
+                                   false>();
+  test_is_applicable_from_function<void(int, char*, double) noexcept,
+                                   const volatile std::tuple<int, char*, double>,
+                                   false>();
+  test_is_applicable_from_function<void(int, char*, double) noexcept,
+                                   const volatile std::tuple<int, char*, double>&,
+                                   false>();
+
+  test_is_applicable<NoExceptCallable<bool>, volatile std::tuple<int, char*, double>, false>();
+  test_is_applicable<NoExceptCallable<bool>, volatile std::tuple<int, char*, double>&, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile std::tuple<int, char*, double>, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile std::tuple<int, char*, double>&, false>();
+
+  // test pair
+  test_is_applicable_from_function<void(int, long), volatile std::pair<int, long>, false>();
+  test_is_applicable_from_function<void(int, long), volatile std::pair<int, long>&, false>();
+  test_is_applicable_from_function<void(int, long), const volatile std::pair<int, long>, false>();
+  test_is_applicable_from_function<void(int, long), const volatile std::pair<int, long>&, false>();
+  test_is_applicable_from_function<void(int, long) noexcept, volatile std::pair<int, long>, false>();
+  test_is_applicable_from_function<void(int, long) noexcept, volatile std::pair<int, long>&, false>();
+  test_is_applicable_from_function<void(int, long) noexcept, const volatile std::pair<int, long>, false>();
+  test_is_applicable_from_function<void(int, long) noexcept, const volatile std::pair<int, long>&, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, volatile std::pair<int, long>, false>();
+  test_is_applicable<NoExceptCallable<bool>, volatile std::pair<int, long>&, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile std::pair<int, long>, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile std::pair<int, long>&, false>();
+}
+
+void test_invalid_nontuple_types() {
+  // test void
+  test_is_applicable_from_function<void(), void, false>();
+  test_is_applicable_from_function<void(), const void, false>();
+  test_is_applicable_from_function<void(), volatile void, false>();
+  test_is_applicable_from_function<void(), const volatile void, false>();
+  test_is_applicable_from_function<void() noexcept, void, false>();
+  test_is_applicable_from_function<void() noexcept, const void, false>();
+  test_is_applicable_from_function<void() noexcept, volatile void, false>();
+  test_is_applicable_from_function<void() noexcept, const volatile void, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, void, false>();
+  test_is_applicable<NoExceptCallable<bool>, const void, false>();
+  test_is_applicable<NoExceptCallable<bool>, volatile void, false>();
+  test_is_applicable<NoExceptCallable<bool>, const volatile void, false>();
+
+  // test function
+  test_is_applicable_from_function<void(void (&)()), void(), false>();
+  test_is_applicable_from_function<void(void (&)()), void (&)(), false>();
+  test_is_applicable_from_function<void(void (&)()) noexcept, void(), false>();
+  test_is_applicable_from_function<void(void (&)()) noexcept, void (&)(), false>();
+  test_is_applicable_from_function<void(void (&)()), void() const & noexcept, false>();
+  test_is_applicable_from_function<void(void (&)()) noexcept, void() const & noexcept, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, void(), false>();
+  test_is_applicable<NoExceptCallable<bool>, void (&)(), false>();
+  test_is_applicable<NoExceptCallable<bool>, void() const & noexcept, false>();
+
+  // test scalar
+  test_is_applicable_from_function<void(int), int, false>();
+  test_is_applicable_from_function<void(int), int&, false>();
+  test_is_applicable_from_function<void(int), const int, false>();
+  test_is_applicable_from_function<void(int), const int&, false>();
+  test_is_applicable_from_function<void(int) noexcept, int, false>();
+  test_is_applicable_from_function<void(int) noexcept, int&, false>();
+  test_is_applicable_from_function<void(int) noexcept, const int, false>();
+  test_is_applicable_from_function<void(int) noexcept, const int&, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, int, false>();
+  test_is_applicable<NoExceptCallable<bool>, int&, false>();
+  test_is_applicable<NoExceptCallable<bool>, const int, false>();
+  test_is_applicable<NoExceptCallable<bool>, const int&, false>();
+
+  test_is_applicable_from_function<void(void*), void*, false>();
+  test_is_applicable_from_function<void(void*), void*&, false>();
+  test_is_applicable_from_function<void(void*), void* const, false>();
+  test_is_applicable_from_function<void(void*), void* const&, false>();
+  test_is_applicable_from_function<void(void*) noexcept, void*, false>();
+  test_is_applicable_from_function<void(void*) noexcept, void*&, false>();
+  test_is_applicable_from_function<void(void*) noexcept, void* const, false>();
+  test_is_applicable_from_function<void(void*) noexcept, void* const&, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, void*, false>();
+  test_is_applicable<NoExceptCallable<bool>, void*&, false>();
+  test_is_applicable<NoExceptCallable<bool>, void* const, false>();
+  test_is_applicable<NoExceptCallable<bool>, void* const&, false>();
+
+  // test plain aggregate
+  test_is_applicable_from_function<void(), empty_aggregate, false>();
+  test_is_applicable_from_function<void(), empty_aggregate&, false>();
+  test_is_applicable_from_function<void(), const empty_aggregate, false>();
+  test_is_applicable_from_function<void(), const empty_aggregate&, false>();
+  test_is_applicable_from_function<void() noexcept, empty_aggregate, false>();
+  test_is_applicable_from_function<void() noexcept, empty_aggregate&, false>();
+  test_is_applicable_from_function<void() noexcept, const empty_aggregate, false>();
+  test_is_applicable_from_function<void() noexcept, const empty_aggregate&, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, empty_aggregate, false>();
+  test_is_applicable<NoExceptCallable<bool>, empty_aggregate&, false>();
+  test_is_applicable<NoExceptCallable<bool>, const empty_aggregate, false>();
+  test_is_applicable<NoExceptCallable<bool>, const empty_aggregate&, false>();
+
+  // test std::get-able class
+  test_is_applicable_from_function<void(int), derived_from_tuple_int, false>();
+  test_is_applicable_from_function<void(int), derived_from_tuple_int&, false>();
+  test_is_applicable_from_function<void(int), const derived_from_tuple_int, false>();
+  test_is_applicable_from_function<void(int), const derived_from_tuple_int&, false>();
+  test_is_applicable_from_function<void(int) noexcept, derived_from_tuple_int, false>();
+  test_is_applicable_from_function<void(int) noexcept, derived_from_tuple_int&, false>();
+  test_is_applicable_from_function<void(int) noexcept, const derived_from_tuple_int, false>();
+  test_is_applicable_from_function<void(int) noexcept, const derived_from_tuple_int&, false>();
+
+  test_is_applicable<NoExceptCallable<bool>, derived_from_tuple_int, false>();
+  test_is_applicable<NoExceptCallable<bool>, derived_from_tuple_int&, false>();
+  test_is_applicable<NoExceptCallable<bool>, const derived_from_tuple_int, false>();
+  test_is_applicable<NoExceptCallable<bool>, const derived_from_tuple_int&, false>();
+
+  // test built-in array
+  test_is_applicable_from_function<void(int), int[1], false>();
+  test_is_applicable_from_function<void(int), int (&)[1], false>();
+  test_is_applicable_from_function<void(int), const int[1], false>();
+  test_is_applicable_from_function<void(int), const int (&)[1], false>();
+  test_is_applicable_from_function<void(int) noexcept, int[1], false>();
+  test_is_applicable_from_function<void(int) noexcept, int (&)[1], false>();
+  test_is_applicable_from_function<void(int) noexcept, const int[1], false>();
+  test_is_applicable_from_function<void(int) noexcept, const int (&)[1], false>();
+
+  test_is_applicable<NoExceptCallable<bool>, int[1], false>();
+  test_is_applicable<NoExceptCallable<bool>, int (&)[1], false>();
+  test_is_applicable<NoExceptCallable<bool>, const int[1], false>();
+  test_is_applicable<NoExceptCallable<bool>, const int (&)[1], false>();
+}
+
+void test_invalid_invocations() {
+  // test array
+  test_is_applicable<void, std::array<int, 0>, false>();
+  test_is_applicable<void*, std::array<int, 1>, false>();
+  test_is_applicable<int, std::array<int, 2>, false>();
+  test_is_applicable<int&, std::array<int, 3>, false>();
+  test_is_applicable<int(int, int, int, int) const & noexcept, std::array<int, 4>, false>();
+
+  test_is_applicable_from_function<void(int), std::array<int, 0>, false>();
+  test_is_applicable_from_function<void(int), std::array<int, 0>&, false>();
+  test_is_applicable_from_function<void(int), const std::array<int, 0>, false>();
+  test_is_applicable_from_function<void(int), const std::array<int, 0>&, false>();
+  test_is_applicable_from_function<void(int) noexcept, std::array<int, 0>, false>();
+  test_is_applicable_from_function<void(int) noexcept, std::array<int, 0>&, false>();
+  test_is_applicable_from_function<void(int) noexcept, const std::array<int, 0>, false>();
+  test_is_applicable_from_function<void(int) noexcept, const std::array<int, 0>&, false>();
+  test_is_applicable_from_function<void(int, long), std::array<int, 1>, false>();
+  test_is_applicable_from_function<void(int, long), std::array<int, 1>&, false>();
+  test_is_applicable_from_function<void(int, long), const std::array<int, 1>, false>();
+  test_is_applicable_from_function<void(int, long), const std::array<int, 1>&, false>();
+  test_is_applicable_from_function<void(int, long) noexcept, std::array<int, 1>, false>();
+  test_is_applicable_from_function<void(int, long) noexcept, std::array<int, 1>&, false>();
+  test_is_applicable_from_function<void(int, long) noexcept, const std::array<int, 1>, false>();
+  test_is_applicable_from_function<void(int, long) noexcept, const std::array<int, 1>&, false>();
+
+  // test complex
+  test_is_applicable<void, std::complex<float>, false>();
+  test_is_applicable<void*, std::complex<float>, false>();
+  test_is_applicable<int, std::complex<float>, false>();
+  test_is_applicable<int&, std::complex<float>, false>();
+  test_is_applicable<void(float, float) const & noexcept, std::complex<float>, false>();
+
+  test_is_applicable<void, std::complex<double>, false>();
+  test_is_applicable<void*, std::complex<double>, false>();
+  test_is_applicable<int, std::complex<double>, false>();
+  test_is_applicable<int&, std::complex<double>, false>();
+  test_is_applicable<void(double, double) const & noexcept, std::complex<double>, false>();
+
+  test_is_applicable<void, std::complex<long double>, false>();
+  test_is_applicable<void*, std::complex<long double>, false>();
+  test_is_applicable<int, std::complex<long double>, false>();
+  test_is_applicable<int&, std::complex<long double>, false>();
+  test_is_applicable<void(long double, long double) const & noexcept, std::complex<long double>, false>();
+
+  test_is_applicable_from_function<void(float), std::complex<float>, false>();
+  test_is_applicable_from_function<void(float), std::complex<float>&, false>();
+  test_is_applicable_from_function<void(float), const std::complex<float>, false>();
+  test_is_applicable_from_function<void(float), const std::complex<float>&, false>();
+  test_is_applicable_from_function<void(float) noexcept, std::complex<float>, false>();
+  test_is_applicable_from_function<void(float) noexcept, std::complex<float>&, false>();
+  test_is_applicable_from_function<void(float) noexcept, const std::complex<float>, false>();
+  test_is_applicable_from_function<void(float) noexcept, const std::complex<float>&, false>();
+
+  test_is_applicable_from_function<void(double), std::complex<double>, false>();
+  test_is_applicable_from_function<void(double), std::complex<double>&, false>();
+  test_is_applicable_from_function<void(double), const std::complex<double>, false>();
+  test_is_applicable_from_function<void(double), const std::complex<double>&, false>();
+  test_is_applicable_from_function<void(double) noexcept, std::complex<double>, false>();
+  test_is_applicable_from_function<void(double) noexcept, std::complex<double>&, false>();
+  test_is_applicable_from_function<void(double) noexcept, const std::complex<double>, false>();
+  test_is_applicable_from_function<void(double) noexcept, const std::complex<double>&, false>();
+
+  test_is_applicable_from_function<void(long double), std::complex<long double>, false>();
+  test_is_applicable_from_function<void(long double), std::complex<long double>&, false>();
+  test_is_applicable_from_function<void(long double), const std::complex<long double>, false>();
+  test_is_applicable_from_function<void(long double), const std::complex<long double>&, false>();
+  test_is_applicable_from_function<void(long double) noexcept, std::complex<long double>, false>();
+  test_is_applicable_from_function<void(long double) noexcept, std::complex<long double>&, false>();
+  test_is_applicable_from_function<void(long double) noexcept, const std::complex<long double>, false>();
+  test_is_applicable_from_function<void(long double) noexcept, const std::complex<long double>&, false>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+
+  test_is_applicable<void, copyable_subrange, false>();
+  test_is_applicable<void*, copyable_subrange, false>();
+  test_is_applicable<int, copyable_subrange, false>();
+  test_is_applicable<int&, copyable_subrange, false>();
+
+  test_is_applicable_from_function<void(std::default_sentinel_t), copyable_subrange, false>();
+  test_is_applicable_from_function<void(std::default_sentinel_t), copyable_subrange&, false>();
+  test_is_applicable_from_function<int(std::default_sentinel_t), const copyable_subrange, false>();
+  test_is_applicable_from_function<int(std::default_sentinel_t), const copyable_subrange&, false>();
+  test_is_applicable_from_function<void(std::default_sentinel_t) noexcept, copyable_subrange, false>();
+  test_is_applicable_from_function<void(std::default_sentinel_t) noexcept, copyable_subrange&, false>();
+  test_is_applicable_from_function<int(std::default_sentinel_t) noexcept, const copyable_subrange, false>();
+  test_is_applicable_from_function<int(std::default_sentinel_t) noexcept, const copyable_subrange&, false>();
+
+  using move_only_counted_iter = std::counted_iterator<cpp20_input_iterator<int*>>;
+  using move_only_subrange     = std::ranges::subrange<move_only_counted_iter, std::default_sentinel_t>;
+
+  test_is_applicable<void, move_only_subrange, false>();
+  test_is_applicable<void*, move_only_subrange, false>();
+  test_is_applicable<int, move_only_subrange, false>();
+  test_is_applicable<int&, move_only_subrange, false>();
+
+  test_is_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                   move_only_subrange&,
+                                   false>();
+  test_is_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                   const move_only_subrange,
+                                   false>();
+  test_is_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                   const move_only_subrange&,
+                                   false>();
+  test_is_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                   move_only_subrange&,
+                                   false>();
+  test_is_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                   const move_only_subrange,
+                                   false>();
+  test_is_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                   const move_only_subrange&,
+                                   false>();
+
+  test_is_applicable_from_function<void(std::default_sentinel_t), move_only_subrange, false>();
+  test_is_applicable_from_function<void(std::default_sentinel_t), move_only_subrange&, false>();
+  test_is_applicable_from_function<int(std::default_sentinel_t), const move_only_subrange, false>();
+  test_is_applicable_from_function<int(std::default_sentinel_t), const move_only_subrange&, false>();
+  test_is_applicable_from_function<void(std::default_sentinel_t) noexcept, move_only_subrange, false>();
+  test_is_applicable_from_function<void(std::default_sentinel_t) noexcept, move_only_subrange&, false>();
+  test_is_applicable_from_function<int(std::default_sentinel_t) noexcept, const move_only_subrange, false>();
+  test_is_applicable_from_function<int(std::default_sentinel_t) noexcept, const move_only_subrange&, false>();
+
+  // test tuple
+  test_is_applicable<void, std::tuple<>, false>();
+  test_is_applicable<void*, std::tuple<>, false>();
+  test_is_applicable<int, std::tuple<int>, false>();
+  test_is_applicable<int&, std::tuple<int>, false>();
+  test_is_applicable<int() const&, std::tuple<>, false>();
+  test_is_applicable<int() const & noexcept, std::tuple<>, false>();
+
+  test_is_applicable_from_function<int(), std::tuple<int>, false>();
+  test_is_applicable_from_function<int(), std::tuple<int>&, false>();
+  test_is_applicable_from_function<int(), const std::tuple<int>, false>();
+  test_is_applicable_from_function<int(), const std::tuple<int>&, false>();
+  test_is_applicable_from_function<int() noexcept, std::tuple<int>, false>();
+  test_is_applicable_from_function<int() noexcept, std::tuple<int>&, false>();
+  test_is_applicable_from_function<int() noexcept, const std::tuple<int>, false>();
+  test_is_applicable_from_function<int() noexcept, const std::tuple<int>&, false>();
+
+  // test pair
+  test_is_applicable<void, std::pair<int, long>, false>();
+  test_is_applicable<void*, std::pair<int, long>, false>();
+  test_is_applicable<int, std::pair<int, long>, false>();
+  test_is_applicable<int&, std::pair<int, long>, false>();
+
+  test_is_applicable<int(int, long) const&, std::pair<int, long>, false>();
+  test_is_applicable<int(int, long) const & noexcept, std::pair<int, long>, false>();
+
+  test_is_applicable_from_function<int(), std::pair<int, long>, false>();
+  test_is_applicable_from_function<void(int, long, long long), std::pair<int, long>&, false>();
+  test_is_applicable_from_function<int&(int), const std::pair<int, long>, false>();
+  test_is_applicable_from_function<long&(int&, long&), const std::pair<int, long>&, false>();
+  test_is_applicable_from_function<int() noexcept, std::pair<int, long>, false>();
+  test_is_applicable_from_function<void(int, long, long long) noexcept, std::pair<int, long>&, false>();
+  test_is_applicable_from_function<int&(int) noexcept, const std::pair<int, long>, false>();
+  test_is_applicable_from_function<long&(int&, long&) noexcept, const std::pair<int, long>&, false>();
+}
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_applicable.compile.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_applicable.compile.pass.cpp
new file mode 100644
index 0000000000000..de8c8a44c3396
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.rel/is_nothrow_applicable.compile.pass.cpp
@@ -0,0 +1,652 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_nothrow_applicable;
+
+// template<class Fn, class Tuple>
+// constexpr bool is_nothrow_applicable_v = is_nothrow_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_nothrow_applicable() {
+  static_assert(std::is_nothrow_applicable<Fn, Tuple>::value == Expected);
+  static_assert(std::is_nothrow_applicable_v<Fn, Tuple> == Expected);
+
+  static_assert(std::is_base_of_v<std::bool_constant<Expected>, std::is_nothrow_applicable<Fn, Tuple>>);
+  static_assert(std::is_convertible_v<std::is_nothrow_applicable<Fn, Tuple>*, std::bool_constant<Expected>*>);
+}
+
+template <class Func, class Tuple, bool Expected>
+void test_is_nothrow_applicable_from_function() {
+  static_assert(std::is_function_v<Func>);
+
+  test_is_nothrow_applicable<Func, Tuple, Expected>();
+  test_is_nothrow_applicable<Func&, Tuple, Expected>();
+
+  test_is_nothrow_applicable<Func*, Tuple, Expected>();
+  test_is_nothrow_applicable<Func*&, Tuple, Expected>();
+  test_is_nothrow_applicable<Func* const, Tuple, Expected>();
+  test_is_nothrow_applicable<Func* volatile, Tuple, Expected>();
+  test_is_nothrow_applicable<Func* volatile&, Tuple, Expected>();
+  test_is_nothrow_applicable<Func* const volatile, Tuple, Expected>();
+  test_is_nothrow_applicable<Func* const volatile&, Tuple, Expected>();
+}
+
+void test_valid() {
+  // test array
+  test_is_nothrow_applicable_from_function<int() noexcept, std::array<int, 0>, true>();
+  test_is_nothrow_applicable_from_function<int() noexcept, std::array<long, 0>&, true>();
+  test_is_nothrow_applicable_from_function<int() noexcept, const std::array<char, 0>, true>();
+  test_is_nothrow_applicable_from_function<int() noexcept, const std::array<std::array<int, 1>, 0>&, true>();
+
+  test_is_nothrow_applicable_from_function<int(long) noexcept, std::array<int, 1>, true>();
+  test_is_nothrow_applicable_from_function<int&(int) noexcept, std::array<long, 1>&, true>();
+  test_is_nothrow_applicable_from_function<const int && (float) noexcept, const std::array<double, 1>, true>();
+  test_is_nothrow_applicable_from_function<void(double) noexcept, const std::array<char, 1>&, true>();
+
+  test_is_nothrow_applicable_from_function<int(long, int) noexcept, std::array<int, 2>, true>();
+  test_is_nothrow_applicable_from_function<int&(long, int) noexcept, std::array<int, 2>&, true>();
+  test_is_nothrow_applicable_from_function<const int && (long, int) noexcept, const std::array<int, 2>, true>();
+  test_is_nothrow_applicable_from_function<void(long, int) noexcept, const std::array<int, 2>&, true>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::array<int, 0>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::array<int, 1>&, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::array<int, 2>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::array<int, 3>&, true>();
+
+  // test complex
+  test_is_nothrow_applicable_from_function<float(float, float) noexcept, std::complex<float>, true>();
+  test_is_nothrow_applicable_from_function<float(float&, float&) noexcept, std::complex<float>&, true>();
+  test_is_nothrow_applicable_from_function<void(float, float) noexcept, const std::complex<float>, true>();
+  test_is_nothrow_applicable_from_function<double(float, float) noexcept, const std::complex<float>&, true>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::complex<float>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::complex<float>&, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::complex<float>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::complex<float>&, true>();
+
+  test_is_nothrow_applicable_from_function<double(double, double) noexcept, std::complex<double>, true>();
+  test_is_nothrow_applicable_from_function<double&(double&, double&) noexcept, std::complex<double>&, true>();
+  test_is_nothrow_applicable_from_function<void(double, double) noexcept, const std::complex<double>, true>();
+  test_is_nothrow_applicable_from_function<double(double, double) noexcept, const std::complex<double>&, true>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::complex<double>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::complex<double>&, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::complex<double>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::complex<double>&, true>();
+
+  test_is_nothrow_applicable_from_function<long double(long double, long double) noexcept,
+                                           std::complex<long double>,
+                                           true>();
+  test_is_nothrow_applicable_from_function<long double&(long double&, long double&) noexcept,
+                                           std::complex<long double>&,
+                                           true>();
+  test_is_nothrow_applicable_from_function<void(long double, long double) noexcept,
+                                           const std::complex<long double>,
+                                           true>();
+  test_is_nothrow_applicable_from_function<double(long double, long double) noexcept,
+                                           const std::complex<long double>&,
+                                           true>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::complex<long double>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::complex<long double>&, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::complex<long double>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::complex<long double>&, true>();
+
+  // test subrange
+  // Exception specifications may be different among implementations, see [res.on.exception.handling]/5.
+  using copyable_subrange = std::ranges::subrange<int*>;
+  constexpr bool can_nothrow_get_copyable_subrange_lv =
+      noexcept((void)std::get<0>(std::declval<const copyable_subrange&>()),
+               (void)std::get<1>(std::declval<const copyable_subrange&>()));
+  constexpr bool can_nothrow_get_copyable_subrange_rv = noexcept(
+      (void)std::get<0>(std::declval<copyable_subrange>()), (void)std::get<1>(std::declval<copyable_subrange>()));
+
+  test_is_nothrow_applicable_from_function<void(int*, int*) noexcept,
+                                           copyable_subrange,
+                                           can_nothrow_get_copyable_subrange_rv>();
+  test_is_nothrow_applicable_from_function<long(int*, int*) noexcept,
+                                           copyable_subrange&,
+                                           can_nothrow_get_copyable_subrange_lv>();
+  test_is_nothrow_applicable_from_function<int*&(int*, int*) noexcept,
+                                           const copyable_subrange,
+                                           can_nothrow_get_copyable_subrange_lv>();
+  test_is_nothrow_applicable_from_function<int* && (int*, int*) noexcept,
+                                           const copyable_subrange&,
+                                           can_nothrow_get_copyable_subrange_lv>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, copyable_subrange, can_nothrow_get_copyable_subrange_rv>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, copyable_subrange&, can_nothrow_get_copyable_subrange_lv>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const copyable_subrange, can_nothrow_get_copyable_subrange_lv>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const copyable_subrange&, can_nothrow_get_copyable_subrange_lv>();
+
+  using move_only_counted_iter = std::counted_iterator<cpp20_input_iterator<int*>>;
+  using move_only_subrange     = std::ranges::subrange<move_only_counted_iter, std::default_sentinel_t>;
+  constexpr bool can_nothrow_get_move_only_subrange_rv = noexcept(
+      (void)std::get<0>(std::declval<move_only_subrange>()), (void)std::get<1>(std::declval<move_only_subrange>()));
+
+  test_is_nothrow_applicable_from_function<void(move_only_counted_iter&&, std::default_sentinel_t),
+                                           move_only_subrange,
+                                           can_nothrow_get_move_only_subrange_rv>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, move_only_subrange, can_nothrow_get_move_only_subrange_rv>();
+
+  // test tuple
+  test_is_nothrow_applicable_from_function<int() noexcept, std::tuple<>, true>();
+  test_is_nothrow_applicable_from_function<char&() noexcept, std::tuple<>&, true>();
+  test_is_nothrow_applicable_from_function<long && () noexcept, const std::tuple<>, true>();
+  test_is_nothrow_applicable_from_function<void() noexcept, const std::tuple<>&, true>();
+
+  test_is_nothrow_applicable_from_function<int(long, int) noexcept, std::tuple<int, long>, true>();
+  test_is_nothrow_applicable_from_function<int&(long, int) noexcept, std::tuple<int, long>&, true>();
+  test_is_nothrow_applicable_from_function<const int && (long, int) noexcept, const std::tuple<int, long>, true>();
+  test_is_nothrow_applicable_from_function<void(long, int) noexcept, const std::tuple<int, long>&, true>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::tuple<>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::tuple<long>&, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::tuple<int, long>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::tuple<int, double, long>&, true>();
+
+  // test pair
+  test_is_nothrow_applicable_from_function<int(long, int) noexcept, std::pair<int, long>, true>();
+  test_is_nothrow_applicable_from_function<int&(long, int) noexcept, std::pair<int, long>&, true>();
+  test_is_nothrow_applicable_from_function<const int && (long, int) noexcept, const std::pair<int, long>, true>();
+  test_is_nothrow_applicable_from_function<void(long, int) noexcept, const std::pair<int, long>&, true>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::pair<char, wchar_t>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, std::pair<float, long>&, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::pair<int, long>, true>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const std::pair<int, double>&, true>();
+}
+
+void test_potentially_throwing() {
+  // test array
+  test_is_nothrow_applicable_from_function<int(), std::array<int, 0>, false>();
+  test_is_nothrow_applicable_from_function<int(), std::array<long, 0>&, false>();
+  test_is_nothrow_applicable_from_function<int(), const std::array<char, 0>, false>();
+  test_is_nothrow_applicable_from_function<int(), const std::array<std::array<int, 1>, 0>&, false>();
+
+  test_is_nothrow_applicable_from_function<int(long), std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<int&(int), std::array<long, 1>&, false>();
+  test_is_nothrow_applicable_from_function<const int && (float), const std::array<double, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(double), const std::array<char, 1>&, false>();
+
+  test_is_nothrow_applicable_from_function<int(long, int), std::array<int, 2>, false>();
+  test_is_nothrow_applicable_from_function<int&(long, int), std::array<int, 2>&, false>();
+  test_is_nothrow_applicable_from_function<const int && (long, int), const std::array<int, 2>, false>();
+  test_is_nothrow_applicable_from_function<void(long, int), const std::array<int, 2>&, false>();
+
+  test_is_nothrow_applicable<ConstCallable<bool>, std::array<int, 0>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, std::array<int, 1>&, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::array<int, 2>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::array<int, 3>&, false>();
+
+  // test complex
+  test_is_nothrow_applicable_from_function<float(float, float), std::complex<float>, false>();
+  test_is_nothrow_applicable_from_function<float(float&, float&), std::complex<float>&, false>();
+  test_is_nothrow_applicable_from_function<void(float, float), const std::complex<float>, false>();
+  test_is_nothrow_applicable_from_function<double(float, float), const std::complex<float>&, false>();
+
+  test_is_nothrow_applicable<ConstCallable<bool>, std::complex<float>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, std::complex<float>&, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::complex<float>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::complex<float>&, false>();
+
+  test_is_nothrow_applicable_from_function<double(double, double), std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<double&(double&, double&), std::complex<double>&, false>();
+  test_is_nothrow_applicable_from_function<void(double, double), const std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<double(double, double), std::complex<double>&, false>();
+
+  test_is_nothrow_applicable<ConstCallable<bool>, std::complex<double>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, std::complex<double>&, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::complex<double>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::complex<double>&, false>();
+
+  test_is_nothrow_applicable_from_function<long double(long double, long double), std::complex<long double>, false>();
+  test_is_nothrow_applicable_from_function<long double&(long double&, long double&),
+                                           std::complex<long double>&,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(long double, long double), const std::complex<long double>, false>();
+  test_is_nothrow_applicable_from_function<double(long double, long double), const std::complex<long double>&, false>();
+
+  test_is_nothrow_applicable<ConstCallable<bool>, std::complex<long double>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, std::complex<long double>&, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::complex<long double>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::complex<long double>&, false>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+  test_is_nothrow_applicable_from_function<void(int*, int*), copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<long(int*, int*), copyable_subrange&, false>();
+  test_is_nothrow_applicable_from_function<int*&(int*, int*), const copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<int* && (int*, int*), const copyable_subrange&, false>();
+
+  test_is_nothrow_applicable<ConstCallable<bool>, copyable_subrange, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, copyable_subrange&, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const copyable_subrange, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const copyable_subrange&, false>();
+
+  using move_only_counted_iter = std::counted_iterator<cpp20_input_iterator<int*>>;
+  using move_only_subrange     = std::ranges::subrange<move_only_counted_iter, std::default_sentinel_t>;
+  test_is_nothrow_applicable_from_function<void(move_only_counted_iter&&, std::default_sentinel_t),
+                                           move_only_subrange,
+                                           false>();
+
+  test_is_nothrow_applicable<ConstCallable<bool>, move_only_subrange, false>();
+
+  // test tuple
+  test_is_nothrow_applicable_from_function<int(), std::tuple<>, false>();
+  test_is_nothrow_applicable_from_function<char&(), std::tuple<>&, false>();
+  test_is_nothrow_applicable_from_function<long && (), const std::tuple<>, false>();
+  test_is_nothrow_applicable_from_function<void(), const std::tuple<>&, false>();
+
+  test_is_nothrow_applicable_from_function<int(long, int), std::tuple<int, long>, false>();
+  test_is_nothrow_applicable_from_function<int&(long, int), std::tuple<int, long>&, false>();
+  test_is_nothrow_applicable_from_function<const int && (long, int), const std::tuple<int, long>, false>();
+  test_is_nothrow_applicable_from_function<void(long, int), const std::tuple<int, long>&, false>();
+
+  test_is_nothrow_applicable<ConstCallable<bool>, std::tuple<>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, std::tuple<long>&, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::tuple<int, long>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::tuple<int, double, long>&, false>();
+
+  // test pair
+  test_is_nothrow_applicable_from_function<int(long, int), std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<int&(long, int), std::pair<int, long>&, false>();
+  test_is_nothrow_applicable_from_function<const int && (long, int), const std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<void(long, int), const std::pair<int, long>&, false>();
+
+  test_is_nothrow_applicable<ConstCallable<bool>, std::pair<char, wchar_t>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, std::pair<float, long>&, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::pair<int, long>, false>();
+  test_is_nothrow_applicable<ConstCallable<bool>, const std::pair<int, double>&, false>();
+}
+
+void test_volatile() {
+  // test array
+  test_is_nothrow_applicable_from_function<void(int), volatile std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(int), volatile std::array<int, 1>&, false>();
+  test_is_nothrow_applicable_from_function<void(int), const volatile std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(int), const volatile std::array<int, 1>&, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, volatile std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, volatile std::array<int, 1>&, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const volatile std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const volatile std::array<int, 1>&, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile std::array<int, 1>, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile std::array<int, 1>&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile std::array<int, 1>, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile std::array<int, 1>&, false>();
+
+  // test complex
+  test_is_nothrow_applicable_from_function<void(double, double), volatile std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<void(double, double), volatile std::complex<double>&, false>();
+  test_is_nothrow_applicable_from_function<void(double, double), const volatile std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<void(double, double), const volatile std::complex<double>&, false>();
+  test_is_nothrow_applicable_from_function<void(double, double) noexcept, volatile std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<void(double, double) noexcept, volatile std::complex<double>&, false>();
+  test_is_nothrow_applicable_from_function<void(double, double) noexcept, const volatile std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<void(double, double) noexcept,
+                                           const volatile std::complex<double>&,
+                                           false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile std::complex<double>, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile std::complex<double>&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile std::complex<double>, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile std::complex<double>&, false>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+
+  test_is_nothrow_applicable_from_function<void(int*, int*), volatile copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<void(int*, int*), volatile copyable_subrange&, false>();
+  test_is_nothrow_applicable_from_function<void(int*, int*), const volatile copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<void(int*, int*), const volatile copyable_subrange&, false>();
+  test_is_nothrow_applicable_from_function<void(int*, int*) noexcept, volatile copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<void(int*, int*) noexcept, volatile copyable_subrange&, false>();
+  test_is_nothrow_applicable_from_function<void(int*, int*) noexcept, const volatile copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<void(int*, int*) noexcept, const volatile copyable_subrange&, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile copyable_subrange, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile copyable_subrange&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile copyable_subrange, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile copyable_subrange&, false>();
+
+  // test tuple
+  test_is_nothrow_applicable_from_function<void(int, char*, double), volatile std::tuple<int, char*, double>, false>();
+  test_is_nothrow_applicable_from_function<void(int, char*, double), volatile std::tuple<int, char*, double>&, false>();
+  test_is_nothrow_applicable_from_function<void(int, char*, double),
+                                           const volatile std::tuple<int, char*, double>,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(int, char*, double),
+                                           const volatile std::tuple<int, char*, double>&,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(int, char*, double) noexcept,
+                                           volatile std::tuple<int, char*, double>,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(int, char*, double) noexcept,
+                                           volatile std::tuple<int, char*, double>&,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(int, char*, double) noexcept,
+                                           const volatile std::tuple<int, char*, double>,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(int, char*, double) noexcept,
+                                           const volatile std::tuple<int, char*, double>&,
+                                           false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile std::tuple<int, char*, double>, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile std::tuple<int, char*, double>&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile std::tuple<int, char*, double>, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile std::tuple<int, char*, double>&, false>();
+
+  // test pair
+  test_is_nothrow_applicable_from_function<void(int, long), volatile std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long), volatile std::pair<int, long>&, false>();
+  test_is_nothrow_applicable_from_function<void(int, long), const volatile std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long), const volatile std::pair<int, long>&, false>();
+  test_is_nothrow_applicable_from_function<void(int, long) noexcept, volatile std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long) noexcept, volatile std::pair<int, long>&, false>();
+  test_is_nothrow_applicable_from_function<void(int, long) noexcept, const volatile std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long) noexcept, const volatile std::pair<int, long>&, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile std::pair<int, long>, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile std::pair<int, long>&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile std::pair<int, long>, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile std::pair<int, long>&, false>();
+}
+
+void test_invalid_nontuple_types() {
+  // test void
+  test_is_nothrow_applicable_from_function<void(), void, false>();
+  test_is_nothrow_applicable_from_function<void(), const void, false>();
+  test_is_nothrow_applicable_from_function<void(), volatile void, false>();
+  test_is_nothrow_applicable_from_function<void(), const volatile void, false>();
+  test_is_nothrow_applicable_from_function<void() noexcept, void, false>();
+  test_is_nothrow_applicable_from_function<void() noexcept, const void, false>();
+  test_is_nothrow_applicable_from_function<void() noexcept, volatile void, false>();
+  test_is_nothrow_applicable_from_function<void() noexcept, const volatile void, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, void, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const void, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, volatile void, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const volatile void, false>();
+
+  // test function
+  test_is_nothrow_applicable_from_function<void(void (&)()), void(), false>();
+  test_is_nothrow_applicable_from_function<void(void (&)()), void (&)(), false>();
+  test_is_nothrow_applicable_from_function<void(void (&)()) noexcept, void(), false>();
+  test_is_nothrow_applicable_from_function<void(void (&)()) noexcept, void (&)(), false>();
+  test_is_nothrow_applicable_from_function<void(void (&)()), void() const & noexcept, false>();
+  test_is_nothrow_applicable_from_function<void(void (&)()) noexcept, void() const & noexcept, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, void(), false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, void (&)(), false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, void() const & noexcept, false>();
+
+  // test scalar
+  test_is_nothrow_applicable_from_function<void(int), int, false>();
+  test_is_nothrow_applicable_from_function<void(int), int&, false>();
+  test_is_nothrow_applicable_from_function<void(int), const int, false>();
+  test_is_nothrow_applicable_from_function<void(int), const int&, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, int, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, int&, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const int, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const int&, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, int, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, int&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const int, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const int&, false>();
+
+  test_is_nothrow_applicable_from_function<void(void*), void*, false>();
+  test_is_nothrow_applicable_from_function<void(void*), void*&, false>();
+  test_is_nothrow_applicable_from_function<void(void*), void* const, false>();
+  test_is_nothrow_applicable_from_function<void(void*), void* const&, false>();
+  test_is_nothrow_applicable_from_function<void(void*) noexcept, void*, false>();
+  test_is_nothrow_applicable_from_function<void(void*) noexcept, void*&, false>();
+  test_is_nothrow_applicable_from_function<void(void*) noexcept, void* const, false>();
+  test_is_nothrow_applicable_from_function<void(void*) noexcept, void* const&, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, void*, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, void*&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, void* const, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, void* const&, false>();
+
+  // test plain aggregate
+  test_is_nothrow_applicable_from_function<void(), empty_aggregate, false>();
+  test_is_nothrow_applicable_from_function<void(), empty_aggregate&, false>();
+  test_is_nothrow_applicable_from_function<void(), const empty_aggregate, false>();
+  test_is_nothrow_applicable_from_function<void(), const empty_aggregate&, false>();
+  test_is_nothrow_applicable_from_function<void() noexcept, empty_aggregate, false>();
+  test_is_nothrow_applicable_from_function<void() noexcept, empty_aggregate&, false>();
+  test_is_nothrow_applicable_from_function<void() noexcept, const empty_aggregate, false>();
+  test_is_nothrow_applicable_from_function<void() noexcept, const empty_aggregate&, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, empty_aggregate, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, empty_aggregate&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const empty_aggregate, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const empty_aggregate&, false>();
+
+  // test std::get-able class
+  test_is_nothrow_applicable_from_function<void(int), derived_from_tuple_int, false>();
+  test_is_nothrow_applicable_from_function<void(int), derived_from_tuple_int&, false>();
+  test_is_nothrow_applicable_from_function<void(int), const derived_from_tuple_int, false>();
+  test_is_nothrow_applicable_from_function<void(int), const derived_from_tuple_int&, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, derived_from_tuple_int, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, derived_from_tuple_int&, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const derived_from_tuple_int, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const derived_from_tuple_int&, false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, derived_from_tuple_int, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, derived_from_tuple_int&, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const derived_from_tuple_int, false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const derived_from_tuple_int&, false>();
+
+  // test built-in array
+  test_is_nothrow_applicable_from_function<void(int), int[1], false>();
+  test_is_nothrow_applicable_from_function<void(int), int (&)[1], false>();
+  test_is_nothrow_applicable_from_function<void(int), const int[1], false>();
+  test_is_nothrow_applicable_from_function<void(int), const int (&)[1], false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, int[1], false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, int (&)[1], false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const int[1], false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const int (&)[1], false>();
+
+  test_is_nothrow_applicable<NoExceptCallable<bool>, int[1], false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, int (&)[1], false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const int[1], false>();
+  test_is_nothrow_applicable<NoExceptCallable<bool>, const int (&)[1], false>();
+}
+
+void test_invalid_invocations() {
+  // test array
+  test_is_nothrow_applicable<void, std::array<int, 0>, false>();
+  test_is_nothrow_applicable<void*, std::array<int, 1>, false>();
+  test_is_nothrow_applicable<int, std::array<int, 2>, false>();
+  test_is_nothrow_applicable<int&, std::array<int, 3>, false>();
+  test_is_nothrow_applicable<int(int, int, int, int) const & noexcept, std::array<int, 4>, false>();
+
+  test_is_nothrow_applicable_from_function<void(int), std::array<int, 0>, false>();
+  test_is_nothrow_applicable_from_function<void(int), std::array<int, 0>&, false>();
+  test_is_nothrow_applicable_from_function<void(int), const std::array<int, 0>, false>();
+  test_is_nothrow_applicable_from_function<void(int), const std::array<int, 0>&, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, std::array<int, 0>, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, std::array<int, 0>&, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const std::array<int, 0>, false>();
+  test_is_nothrow_applicable_from_function<void(int) noexcept, const std::array<int, 0>&, false>();
+  test_is_nothrow_applicable_from_function<void(int, long), std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long), std::array<int, 1>&, false>();
+  test_is_nothrow_applicable_from_function<void(int, long), const std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long), const std::array<int, 1>&, false>();
+  test_is_nothrow_applicable_from_function<void(int, long) noexcept, std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long) noexcept, std::array<int, 1>&, false>();
+  test_is_nothrow_applicable_from_function<void(int, long) noexcept, const std::array<int, 1>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long) noexcept, const std::array<int, 1>&, false>();
+
+  // test complex
+  test_is_nothrow_applicable<void, std::complex<float>, false>();
+  test_is_nothrow_applicable<void*, std::complex<float>, false>();
+  test_is_nothrow_applicable<int, std::complex<float>, false>();
+  test_is_nothrow_applicable<int&, std::complex<float>, false>();
+  test_is_nothrow_applicable<void(float, float) const & noexcept, std::complex<float>, false>();
+
+  test_is_nothrow_applicable<void, std::complex<double>, false>();
+  test_is_nothrow_applicable<void*, std::complex<double>, false>();
+  test_is_nothrow_applicable<int, std::complex<double>, false>();
+  test_is_nothrow_applicable<int&, std::complex<double>, false>();
+  test_is_nothrow_applicable<void(double, double) const & noexcept, std::complex<double>, false>();
+
+  test_is_nothrow_applicable<void, std::complex<long double>, false>();
+  test_is_nothrow_applicable<void*, std::complex<long double>, false>();
+  test_is_nothrow_applicable<int, std::complex<long double>, false>();
+  test_is_nothrow_applicable<int&, std::complex<long double>, false>();
+  test_is_nothrow_applicable<void(long double, long double) const & noexcept, std::complex<long double>, false>();
+
+  test_is_nothrow_applicable_from_function<void(float), std::complex<float>, false>();
+  test_is_nothrow_applicable_from_function<void(float), std::complex<float>&, false>();
+  test_is_nothrow_applicable_from_function<void(float), const std::complex<float>, false>();
+  test_is_nothrow_applicable_from_function<void(float), const std::complex<float>&, false>();
+  test_is_nothrow_applicable_from_function<void(float) noexcept, std::complex<float>, false>();
+  test_is_nothrow_applicable_from_function<void(float) noexcept, std::complex<float>&, false>();
+  test_is_nothrow_applicable_from_function<void(float) noexcept, const std::complex<float>, false>();
+  test_is_nothrow_applicable_from_function<void(float) noexcept, const std::complex<float>&, false>();
+
+  test_is_nothrow_applicable_from_function<void(double), std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<void(double), std::complex<double>&, false>();
+  test_is_nothrow_applicable_from_function<void(double), const std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<void(double), const std::complex<double>&, false>();
+  test_is_nothrow_applicable_from_function<void(double) noexcept, std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<void(double) noexcept, std::complex<double>&, false>();
+  test_is_nothrow_applicable_from_function<void(double) noexcept, const std::complex<double>, false>();
+  test_is_nothrow_applicable_from_function<void(double) noexcept, const std::complex<double>&, false>();
+
+  test_is_nothrow_applicable_from_function<void(long double), std::complex<long double>, false>();
+  test_is_nothrow_applicable_from_function<void(long double), std::complex<long double>&, false>();
+  test_is_nothrow_applicable_from_function<void(long double), const std::complex<long double>, false>();
+  test_is_nothrow_applicable_from_function<void(long double), const std::complex<long double>&, false>();
+  test_is_nothrow_applicable_from_function<void(long double) noexcept, std::complex<long double>, false>();
+  test_is_nothrow_applicable_from_function<void(long double) noexcept, std::complex<long double>&, false>();
+  test_is_nothrow_applicable_from_function<void(long double) noexcept, const std::complex<long double>, false>();
+  test_is_nothrow_applicable_from_function<void(long double) noexcept, const std::complex<long double>&, false>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+
+  test_is_nothrow_applicable<void, copyable_subrange, false>();
+  test_is_nothrow_applicable<void*, copyable_subrange, false>();
+  test_is_nothrow_applicable<int, copyable_subrange, false>();
+  test_is_nothrow_applicable<int&, copyable_subrange, false>();
+
+  test_is_nothrow_applicable_from_function<void(std::default_sentinel_t), copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<void(std::default_sentinel_t), copyable_subrange&, false>();
+  test_is_nothrow_applicable_from_function<int(std::default_sentinel_t), const copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<int(std::default_sentinel_t), const copyable_subrange&, false>();
+  test_is_nothrow_applicable_from_function<void(std::default_sentinel_t) noexcept, copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<void(std::default_sentinel_t) noexcept, copyable_subrange&, false>();
+  test_is_nothrow_applicable_from_function<int(std::default_sentinel_t) noexcept, const copyable_subrange, false>();
+  test_is_nothrow_applicable_from_function<int(std::default_sentinel_t) noexcept, const copyable_subrange&, false>();
+
+  using move_only_counted_iter = std::counted_iterator<cpp20_input_iterator<int*>>;
+  using move_only_subrange     = std::ranges::subrange<move_only_counted_iter, std::default_sentinel_t>;
+
+  test_is_nothrow_applicable<void, move_only_subrange, false>();
+  test_is_nothrow_applicable<void*, move_only_subrange, false>();
+  test_is_nothrow_applicable<int, move_only_subrange, false>();
+  test_is_nothrow_applicable<int&, move_only_subrange, false>();
+
+  test_is_nothrow_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                           move_only_subrange&,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                           const move_only_subrange,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                           const move_only_subrange&,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                           move_only_subrange&,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                           const move_only_subrange,
+                                           false>();
+  test_is_nothrow_applicable_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                           const move_only_subrange&,
+                                           false>();
+
+  test_is_nothrow_applicable_from_function<void(std::default_sentinel_t), move_only_subrange, false>();
+  test_is_nothrow_applicable_from_function<void(std::default_sentinel_t), move_only_subrange&, false>();
+  test_is_nothrow_applicable_from_function<int(std::default_sentinel_t), const move_only_subrange, false>();
+  test_is_nothrow_applicable_from_function<int(std::default_sentinel_t), const move_only_subrange&, false>();
+  test_is_nothrow_applicable_from_function<void(std::default_sentinel_t) noexcept, move_only_subrange, false>();
+  test_is_nothrow_applicable_from_function<void(std::default_sentinel_t) noexcept, move_only_subrange&, false>();
+  test_is_nothrow_applicable_from_function<int(std::default_sentinel_t) noexcept, const move_only_subrange, false>();
+  test_is_nothrow_applicable_from_function<int(std::default_sentinel_t) noexcept, const move_only_subrange&, false>();
+
+  // test tuple
+  test_is_nothrow_applicable<void, std::tuple<>, false>();
+  test_is_nothrow_applicable<void*, std::tuple<>, false>();
+  test_is_nothrow_applicable<int, std::tuple<int>, false>();
+  test_is_nothrow_applicable<int&, std::tuple<int>, false>();
+  test_is_nothrow_applicable<int() const&, std::tuple<>, false>();
+  test_is_nothrow_applicable<int() const & noexcept, std::tuple<>, false>();
+
+  test_is_nothrow_applicable_from_function<int(), std::tuple<int>, false>();
+  test_is_nothrow_applicable_from_function<int(), std::tuple<int>&, false>();
+  test_is_nothrow_applicable_from_function<int(), const std::tuple<int>, false>();
+  test_is_nothrow_applicable_from_function<int(), const std::tuple<int>&, false>();
+  test_is_nothrow_applicable_from_function<int() noexcept, std::tuple<int>, false>();
+  test_is_nothrow_applicable_from_function<int() noexcept, std::tuple<int>&, false>();
+  test_is_nothrow_applicable_from_function<int() noexcept, const std::tuple<int>, false>();
+  test_is_nothrow_applicable_from_function<int() noexcept, const std::tuple<int>&, false>();
+
+  // test pair
+  test_is_nothrow_applicable<void, std::pair<int, long>, false>();
+  test_is_nothrow_applicable<void*, std::pair<int, long>, false>();
+  test_is_nothrow_applicable<int, std::pair<int, long>, false>();
+  test_is_nothrow_applicable<int&, std::pair<int, long>, false>();
+
+  test_is_nothrow_applicable<int(int, long) const&, std::pair<int, long>, false>();
+  test_is_nothrow_applicable<int(int, long) const & noexcept, std::pair<int, long>, false>();
+
+  test_is_nothrow_applicable_from_function<int(), std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long, long long), std::pair<int, long>&, false>();
+  test_is_nothrow_applicable_from_function<int&(int), const std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<long&(int&, long&), const std::pair<int, long>&, false>();
+  test_is_nothrow_applicable_from_function<int() noexcept, std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<void(int, long, long long) noexcept, std::pair<int, long>&, false>();
+  test_is_nothrow_applicable_from_function<int&(int) noexcept, const std::pair<int, long>, false>();
+  test_is_nothrow_applicable_from_function<long&(int&, long&) noexcept, const std::pair<int, long>&, false>();
+}
diff --git a/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/apply_result.compile.pass.cpp b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/apply_result.compile.pass.cpp
new file mode 100644
index 0000000000000..21ec35aba8a0a
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.trans/meta.trans.other/apply_result.compile.pass.cpp
@@ -0,0 +1,629 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 apply_result;
+
+// template<class Fn, class Tuple>
+// using apply_result_t = typename apply_result<T, U>::type;
+
+#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>
+concept apply_result_has_member_type = requires { typename std::apply_result<Fn, Tuple>::type; };
+
+template <class Fn, class Tuple>
+concept apply_result_t_is_valid = requires { typename std::apply_result_t<Fn, Tuple>; };
+
+template <class Fn, class Tuple, class Expected>
+void test_valid_apply_result() {
+  static_assert(apply_result_has_member_type<Fn, Tuple>);
+  static_assert(apply_result_t_is_valid<Fn, Tuple>);
+  static_assert(std::is_same_v<typename std::apply_result<Fn, Tuple>::type, Expected>);
+  static_assert(std::is_same_v<std::apply_result_t<Fn, Tuple>, Expected>);
+}
+
+template <class Func, class Tuple, class Expected>
+void test_valid_apply_result_from_function() {
+  static_assert(std::is_function_v<Func>);
+
+  test_valid_apply_result<Func, Tuple, Expected>();
+  test_valid_apply_result<Func&, Tuple, Expected>();
+
+  test_valid_apply_result<Func*, Tuple, Expected>();
+  test_valid_apply_result<Func*&, Tuple, Expected>();
+  test_valid_apply_result<Func* const, Tuple, Expected>();
+  test_valid_apply_result<Func* const&, Tuple, Expected>();
+  test_valid_apply_result<Func* volatile, Tuple, Expected>();
+  test_valid_apply_result<Func* volatile&, Tuple, Expected>();
+  test_valid_apply_result<Func* const volatile, Tuple, Expected>();
+  test_valid_apply_result<Func* const volatile&, Tuple, Expected>();
+}
+
+template <class Fn, class Tuple>
+void test_invalid_apply_result() {
+  static_assert(!apply_result_has_member_type<Fn, Tuple>);
+  static_assert(!apply_result_t_is_valid<Fn, Tuple>);
+}
+
+template <class Func, class Tuple>
+void test_invalid_apply_result_from_function() {
+  static_assert(std::is_function_v<Func>);
+
+  test_invalid_apply_result<Func, Tuple>();
+  test_invalid_apply_result<Func&, Tuple>();
+
+  test_invalid_apply_result<Func*, Tuple>();
+  test_invalid_apply_result<Func*&, Tuple>();
+  test_invalid_apply_result<Func* const, Tuple>();
+  test_invalid_apply_result<Func* const&, Tuple>();
+  test_invalid_apply_result<Func* volatile, Tuple>();
+  test_invalid_apply_result<Func* volatile&, Tuple>();
+  test_invalid_apply_result<Func* const volatile, Tuple>();
+  test_invalid_apply_result<Func* const volatile&, Tuple>();
+}
+
+void test_valid() {
+  // test array
+  test_valid_apply_result_from_function<int(), std::array<int, 0>, int>();
+  test_valid_apply_result_from_function<int(), std::array<long, 0>&, int>();
+  test_valid_apply_result_from_function<int(), const std::array<char, 0>, int>();
+  test_valid_apply_result_from_function<int(), const std::array<std::array<int, 1>, 0>&, int>();
+  test_valid_apply_result_from_function<int() noexcept, std::array<int, 0>, int>();
+  test_valid_apply_result_from_function<int() noexcept, std::array<long, 0>&, int>();
+  test_valid_apply_result_from_function<int() noexcept, const std::array<char, 0>, int>();
+  test_valid_apply_result_from_function<int() noexcept, const std::array<std::array<int, 1>, 0>&, int>();
+
+  test_valid_apply_result_from_function<int(long), std::array<int, 1>, int>();
+  test_valid_apply_result_from_function<int&(int), std::array<long, 1>&, int&>();
+  test_valid_apply_result_from_function<const int && (float), const std::array<double, 1>, const int&&>();
+  test_valid_apply_result_from_function<void(double), const std::array<char, 1>&, void>();
+  test_valid_apply_result_from_function<int(long) noexcept, std::array<int, 1>, int>();
+  test_valid_apply_result_from_function<int&(int) noexcept, std::array<long, 1>&, int&>();
+  test_valid_apply_result_from_function<const int && (float) noexcept, const std::array<double, 1>, const int&&>();
+  test_valid_apply_result_from_function<void(double) noexcept, const std::array<char, 1>&, void>();
+
+  test_valid_apply_result_from_function<int(long, int), std::array<int, 2>, int>();
+  test_valid_apply_result_from_function<int&(long, int), std::array<int, 2>&, int&>();
+  test_valid_apply_result_from_function<const int && (long, int), const std::array<int, 2>, const int&&>();
+  test_valid_apply_result_from_function<void(long, int), const std::array<int, 2>&, void>();
+  test_valid_apply_result_from_function<int(long, int) noexcept, std::array<int, 2>, int>();
+  test_valid_apply_result_from_function<int&(long, int) noexcept, std::array<int, 2>&, int&>();
+  test_valid_apply_result_from_function<const int && (long, int) noexcept, const std::array<int, 2>, const int&&>();
+  test_valid_apply_result_from_function<void(long, int) noexcept, const std::array<int, 2>&, void>();
+
+  test_valid_apply_result<ConstCallable<bool>, std::array<int, 0>, bool>();
+  test_valid_apply_result<ConstCallable<signed char>, std::array<int, 1>&, signed char>();
+  test_valid_apply_result<ConstCallable<short>, const std::array<int, 2>, short>();
+  test_valid_apply_result<ConstCallable<int>, const std::array<int, 3>&, int>();
+
+  test_valid_apply_result<NoExceptCallable<bool>, std::array<int, 0>, bool>();
+  test_valid_apply_result<NoExceptCallable<unsigned char>, std::array<int, 1>&, unsigned char>();
+  test_valid_apply_result<NoExceptCallable<unsigned short>, const std::array<int, 2>, unsigned short>();
+  test_valid_apply_result<NoExceptCallable<unsigned int>, const std::array<int, 3>&, unsigned int>();
+
+  // test complex
+  test_valid_apply_result_from_function<float(float, float), std::complex<float>, float>();
+  test_valid_apply_result_from_function<float(float&, float&), std::complex<float>&, float>();
+  test_valid_apply_result_from_function<void(float, float), const std::complex<float>, void>();
+  test_valid_apply_result_from_function<double(float, float), const std::complex<float>&, double>();
+  test_valid_apply_result_from_function<float(float, float) noexcept, std::complex<float>, float>();
+  test_valid_apply_result_from_function<float(float&, float&) noexcept, std::complex<float>&, float>();
+  test_valid_apply_result_from_function<void(float, float) noexcept, const std::complex<float>, void>();
+  test_valid_apply_result_from_function<double(float, float) noexcept, const std::complex<float>&, double>();
+
+  test_valid_apply_result<ConstCallable<bool>, std::complex<float>, bool>();
+  test_valid_apply_result<ConstCallable<signed char>, std::complex<float>&, signed char>();
+  test_valid_apply_result<ConstCallable<int>, const std::complex<float>, int>();
+  test_valid_apply_result<ConstCallable<short>, const std::complex<float>&, short>();
+
+  test_valid_apply_result<NoExceptCallable<unsigned long>, std::complex<float>, unsigned long>();
+  test_valid_apply_result<NoExceptCallable<bool>, std::complex<float>&, bool>();
+  test_valid_apply_result<NoExceptCallable<unsigned int>, const std::complex<float>, unsigned int>();
+  test_valid_apply_result<NoExceptCallable<unsigned short>, const std::complex<float>&, unsigned short>();
+
+  test_valid_apply_result_from_function<double(double, double), std::complex<double>, double>();
+  test_valid_apply_result_from_function<double&(double&, double&), std::complex<double>&, double&>();
+  test_valid_apply_result_from_function<void(double, double), const std::complex<double>, void>();
+  test_valid_apply_result_from_function<double(double, double), const std::complex<double>&, double>();
+  test_valid_apply_result_from_function<double(double, double) noexcept, std::complex<double>, double>();
+  test_valid_apply_result_from_function<double&(double&, double&) noexcept, std::complex<double>&, double&>();
+  test_valid_apply_result_from_function<void(double, double) noexcept, const std::complex<double>, void>();
+  test_valid_apply_result_from_function<double(double, double) noexcept, const std::complex<double>&, double>();
+
+  test_valid_apply_result<ConstCallable<bool>, std::complex<double>, bool>();
+  test_valid_apply_result<ConstCallable<signed char>, std::complex<double>&, signed char>();
+  test_valid_apply_result<ConstCallable<short>, const std::complex<double>, short>();
+  test_valid_apply_result<ConstCallable<int>, const std::complex<double>&, int>();
+
+  test_valid_apply_result<NoExceptCallable<unsigned short>, std::complex<double>, unsigned short>();
+  test_valid_apply_result<NoExceptCallable<unsigned long>, std::complex<double>&, unsigned long>();
+  test_valid_apply_result<NoExceptCallable<bool>, const std::complex<double>, bool>();
+  test_valid_apply_result<NoExceptCallable<unsigned char>, const std::complex<double>&, unsigned char>();
+
+  test_valid_apply_result_from_function<long double(long double, long double),
+                                        std::complex<long double>,
+                                        long double>();
+  test_valid_apply_result_from_function<long double&(long double&, long double&),
+                                        std::complex<long double>&,
+                                        long double&>();
+  test_valid_apply_result_from_function<void(long double, long double), const std::complex<long double>, void>();
+  test_valid_apply_result_from_function<double(long double, long double), const std::complex<long double>&, double>();
+  test_valid_apply_result_from_function<long double(long double, long double) noexcept,
+                                        std::complex<long double>,
+                                        long double>();
+  test_valid_apply_result_from_function<long double&(long double&, long double&) noexcept,
+                                        std::complex<long double>&,
+                                        long double&>();
+  test_valid_apply_result_from_function<void(long double, long double) noexcept,
+                                        const std::complex<long double>,
+                                        void>();
+  test_valid_apply_result_from_function<double(long double, long double) noexcept,
+                                        const std::complex<long double>&,
+                                        double>();
+
+  test_valid_apply_result<ConstCallable<bool>, std::complex<long double>, bool>();
+  test_valid_apply_result<ConstCallable<signed char>, std::complex<long double>&, signed char>();
+  test_valid_apply_result<ConstCallable<short>, const std::complex<long double>, short>();
+  test_valid_apply_result<ConstCallable<int>, const std::complex<long double>&, int>();
+
+  test_valid_apply_result<NoExceptCallable<bool>, std::complex<long double>, bool>();
+  test_valid_apply_result<NoExceptCallable<unsigned char>, std::complex<long double>&, unsigned char>();
+  test_valid_apply_result<NoExceptCallable<unsigned short>, const std::complex<long double>, unsigned short>();
+  test_valid_apply_result<NoExceptCallable<unsigned int>, const std::complex<long double>&, unsigned int>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+
+  test_valid_apply_result_from_function<void(int*, int*), copyable_subrange, void>();
+  test_valid_apply_result_from_function<long(int*, int*), copyable_subrange&, long>();
+  test_valid_apply_result_from_function<int*&(int*, int*), const copyable_subrange, int*&>();
+  test_valid_apply_result_from_function<int* && (int*, int*), const copyable_subrange&, int*&&>();
+  test_valid_apply_result_from_function<void(int*, int*) noexcept, copyable_subrange, void>();
+  test_valid_apply_result_from_function<long(int*, int*) noexcept, copyable_subrange&, long>();
+  test_valid_apply_result_from_function<int*&(int*, int*) noexcept, const copyable_subrange, int*&>();
+  test_valid_apply_result_from_function<int* && (int*, int*) noexcept, const copyable_subrange&, int*&&>();
+
+  test_valid_apply_result<ConstCallable<bool>, copyable_subrange, bool>();
+  test_valid_apply_result<ConstCallable<unsigned char>, copyable_subrange&, unsigned char>();
+  test_valid_apply_result<ConstCallable<short>, const copyable_subrange, short>();
+  test_valid_apply_result<ConstCallable<unsigned long>, const copyable_subrange&, unsigned long>();
+
+  test_valid_apply_result<NoExceptCallable<signed char>, copyable_subrange, signed char>();
+  test_valid_apply_result<NoExceptCallable<unsigned int>, copyable_subrange&, unsigned int>();
+  test_valid_apply_result<NoExceptCallable<long long>, const copyable_subrange, long long>();
+  test_valid_apply_result<NoExceptCallable<unsigned short>, const copyable_subrange&, unsigned short>();
+
+  using move_only_counted_iter = std::counted_iterator<cpp20_input_iterator<int*>>;
+  using move_only_subrange     = std::ranges::subrange<move_only_counted_iter, std::default_sentinel_t>;
+
+  test_valid_apply_result_from_function<void(move_only_counted_iter&&, std::default_sentinel_t),
+                                        move_only_subrange,
+                                        void>();
+  test_valid_apply_result_from_function<void*(move_only_counted_iter&&, std::default_sentinel_t) noexcept,
+                                        move_only_subrange,
+                                        void*>();
+
+  test_valid_apply_result<ConstCallable<long long>, move_only_subrange, long long>();
+
+  test_valid_apply_result<NoExceptCallable<unsigned long long>, move_only_subrange, unsigned long long>();
+
+  // test tuple
+  test_valid_apply_result_from_function<int(), std::tuple<>, int>();
+  test_valid_apply_result_from_function<char&(), std::tuple<>&, char&>();
+  test_valid_apply_result_from_function<long && (), const std::tuple<>, long&&>();
+  test_valid_apply_result_from_function<void(), const std::tuple<>&, void>();
+  test_valid_apply_result_from_function<int() noexcept, std::tuple<>, int>();
+  test_valid_apply_result_from_function<char&() noexcept, std::tuple<>&, char&>();
+  test_valid_apply_result_from_function<long && () noexcept, const std::tuple<>, long&&>();
+  test_valid_apply_result_from_function<void() noexcept, const std::tuple<>&, void>();
+
+  test_valid_apply_result_from_function<int(long, int), std::tuple<int, long>, int>();
+  test_valid_apply_result_from_function<int&(long, int), std::tuple<int, long>&, int&>();
+  test_valid_apply_result_from_function<const int && (long, int), const std::tuple<int, long>, const int&&>();
+  test_valid_apply_result_from_function<void(long, int), const std::tuple<int, long>&, void>();
+  test_valid_apply_result_from_function<int(long, int) noexcept, std::tuple<int, long>, int>();
+  test_valid_apply_result_from_function<int&(long, int) noexcept, std::tuple<int, long>&, int&>();
+  test_valid_apply_result_from_function<const int && (long, int) noexcept, const std::tuple<int, long>, const int&&>();
+  test_valid_apply_result_from_function<void(long, int) noexcept, const std::tuple<int, long>&, void>();
+
+  test_valid_apply_result<ConstCallable<unsigned long long>, std::tuple<>, unsigned long long>();
+  test_valid_apply_result<ConstCallable<unsigned long>, std::tuple<long>&, unsigned long>();
+  test_valid_apply_result<ConstCallable<unsigned int>, const std::tuple<int, long>, unsigned int>();
+  test_valid_apply_result<ConstCallable<unsigned short>, const std::tuple<int, double, long>&, unsigned short>();
+
+  test_valid_apply_result<NoExceptCallable<long long>, std::tuple<>, long long>();
+  test_valid_apply_result<NoExceptCallable<long>, std::tuple<long>&, long>();
+  test_valid_apply_result<NoExceptCallable<int>, const std::tuple<int, long>, int>();
+  test_valid_apply_result<NoExceptCallable<short>, const std::tuple<int, double, long>&, short>();
+
+  // test pair
+  test_valid_apply_result_from_function<int(long, int), std::pair<int, long>, int>();
+  test_valid_apply_result_from_function<int&(long, int), std::pair<int, long>&, int&>();
+  test_valid_apply_result_from_function<const int && (long, int), const std::pair<int, long>, const int&&>();
+  test_valid_apply_result_from_function<void(long, int), const std::pair<int, long>&, void>();
+  test_valid_apply_result_from_function<int(long, int) noexcept, std::pair<int, long>, int>();
+  test_valid_apply_result_from_function<int&(long, int) noexcept, std::pair<int, long>&, int&>();
+  test_valid_apply_result_from_function<const int && (long, int) noexcept, const std::pair<int, long>, const int&&>();
+  test_valid_apply_result_from_function<void(long, int) noexcept, const std::pair<int, long>&, void>();
+
+  test_valid_apply_result<ConstCallable<bool>, std::pair<char, wchar_t>, bool>();
+  test_valid_apply_result<ConstCallable<unsigned char>, std::pair<float, long>&, unsigned char>();
+  test_valid_apply_result<ConstCallable<unsigned int>, const std::pair<int, long>, unsigned int>();
+  test_valid_apply_result<ConstCallable<unsigned short>, const std::pair<int, double>&, unsigned short>();
+
+  test_valid_apply_result<NoExceptCallable<int>, std::pair<char, wchar_t>, int>();
+  test_valid_apply_result<NoExceptCallable<short>, std::pair<float, long>&, short>();
+  test_valid_apply_result<NoExceptCallable<long>, const std::pair<int, long>, long>();
+  test_valid_apply_result<NoExceptCallable<long long>, const std::pair<int, double>&, long long>();
+}
+
+void test_volatile() {
+  // test array
+  test_invalid_apply_result_from_function<void(int), volatile std::array<int, 1>>();
+  test_invalid_apply_result_from_function<void(int), volatile std::array<int, 1>&>();
+  test_invalid_apply_result_from_function<void(int), const volatile std::array<int, 1>>();
+  test_invalid_apply_result_from_function<void(int), const volatile std::array<int, 1>&>();
+  test_invalid_apply_result_from_function<void(int) noexcept, volatile std::array<int, 1>>();
+  test_invalid_apply_result_from_function<void(int) noexcept, volatile std::array<int, 1>&>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const volatile std::array<int, 1>>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const volatile std::array<int, 1>&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile std::array<int, 1>>();
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile std::array<int, 1>&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile std::array<int, 1>>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile std::array<int, 1>&>();
+
+  // test complex
+  test_invalid_apply_result_from_function<void(double, double), volatile std::complex<double>>();
+  test_invalid_apply_result_from_function<void(double, double), volatile std::complex<double>&>();
+  test_invalid_apply_result_from_function<void(double, double), const volatile std::complex<double>>();
+  test_invalid_apply_result_from_function<void(double, double), const volatile std::complex<double>&>();
+  test_invalid_apply_result_from_function<void(double, double) noexcept, volatile std::complex<double>>();
+  test_invalid_apply_result_from_function<void(double, double) noexcept, volatile std::complex<double>&>();
+  test_invalid_apply_result_from_function<void(double, double) noexcept, const volatile std::complex<double>>();
+  test_invalid_apply_result_from_function<void(double, double) noexcept, const volatile std::complex<double>&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile std::complex<double>>();
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile std::complex<double>&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile std::complex<double>>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile std::complex<double>&>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+
+  test_invalid_apply_result_from_function<void(int*, int*), volatile copyable_subrange>();
+  test_invalid_apply_result_from_function<void(int*, int*), volatile copyable_subrange&>();
+  test_invalid_apply_result_from_function<void(int*, int*), const volatile copyable_subrange>();
+  test_invalid_apply_result_from_function<void(int*, int*), const volatile copyable_subrange&>();
+  test_invalid_apply_result_from_function<void(int*, int*) noexcept, volatile copyable_subrange>();
+  test_invalid_apply_result_from_function<void(int*, int*) noexcept, volatile copyable_subrange&>();
+  test_invalid_apply_result_from_function<void(int*, int*) noexcept, const volatile copyable_subrange>();
+  test_invalid_apply_result_from_function<void(int*, int*) noexcept, const volatile copyable_subrange&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile copyable_subrange>();
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile copyable_subrange&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile copyable_subrange>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile copyable_subrange&>();
+
+  // test tuple
+  test_invalid_apply_result_from_function<void(int, char*, double), volatile std::tuple<int, char*, double>>();
+  test_invalid_apply_result_from_function<void(int, char*, double), volatile std::tuple<int, char*, double>&>();
+  test_invalid_apply_result_from_function<void(int, char*, double), const volatile std::tuple<int, char*, double>>();
+  test_invalid_apply_result_from_function<void(int, char*, double), const volatile std::tuple<int, char*, double>&>();
+  test_invalid_apply_result_from_function<void(int, char*, double) noexcept, volatile std::tuple<int, char*, double>>();
+  test_invalid_apply_result_from_function<void(int, char*, double) noexcept,
+                                          volatile std::tuple<int, char*, double>&>();
+  test_invalid_apply_result_from_function<void(int, char*, double) noexcept,
+                                          const volatile std::tuple<int, char*, double>>();
+  test_invalid_apply_result_from_function<void(int, char*, double) noexcept,
+                                          const volatile std::tuple<int, char*, double>&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile std::tuple<int, char*, double>>();
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile std::tuple<int, char*, double>&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile std::tuple<int, char*, double>>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile std::tuple<int, char*, double>&>();
+
+  // test pair
+  test_invalid_apply_result_from_function<void(int, long), volatile std::pair<int, long>>();
+  test_invalid_apply_result_from_function<void(int, long), volatile std::pair<int, long>&>();
+  test_invalid_apply_result_from_function<void(int, long), const volatile std::pair<int, long>>();
+  test_invalid_apply_result_from_function<void(int, long), const volatile std::pair<int, long>&>();
+  test_invalid_apply_result_from_function<void(int, long) noexcept, volatile std::pair<int, long>>();
+  test_invalid_apply_result_from_function<void(int, long) noexcept, volatile std::pair<int, long>&>();
+  test_invalid_apply_result_from_function<void(int, long) noexcept, const volatile std::pair<int, long>>();
+  test_invalid_apply_result_from_function<void(int, long) noexcept, const volatile std::pair<int, long>&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile std::pair<int, long>>();
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile std::pair<int, long>&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile std::pair<int, long>>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile std::pair<int, long>&>();
+}
+
+void test_invalid_nontuple_types() {
+  // test void
+  test_invalid_apply_result_from_function<void(), void>();
+  test_invalid_apply_result_from_function<void(), const void>();
+  test_invalid_apply_result_from_function<void(), volatile void>();
+  test_invalid_apply_result_from_function<void(), const volatile void>();
+  test_invalid_apply_result_from_function<void() noexcept, void>();
+  test_invalid_apply_result_from_function<void() noexcept, const void>();
+  test_invalid_apply_result_from_function<void() noexcept, volatile void>();
+  test_invalid_apply_result_from_function<void() noexcept, const volatile void>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, void>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const void>();
+  test_invalid_apply_result<NoExceptCallable<bool>, volatile void>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const volatile void>();
+
+  // test function
+  test_invalid_apply_result_from_function<void(void (&)()), void()>();
+  test_invalid_apply_result_from_function<void(void (&)()), void (&)()>();
+  test_invalid_apply_result_from_function<void(void (&)()) noexcept, void()>();
+  test_invalid_apply_result_from_function<void(void (&)()) noexcept, void (&)()>();
+  test_invalid_apply_result_from_function<void(void (&)()), void() const & noexcept>();
+  test_invalid_apply_result_from_function<void(void (&)()) noexcept, void() const & noexcept>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, void()>();
+  test_invalid_apply_result<NoExceptCallable<bool>, void (&)()>();
+  test_invalid_apply_result<NoExceptCallable<bool>, void() const & noexcept>();
+
+  // test scalar
+  test_invalid_apply_result_from_function<void(int), int>();
+  test_invalid_apply_result_from_function<void(int), int&>();
+  test_invalid_apply_result_from_function<void(int), const int>();
+  test_invalid_apply_result_from_function<void(int), const int&>();
+  test_invalid_apply_result_from_function<void(int) noexcept, int>();
+  test_invalid_apply_result_from_function<void(int) noexcept, int&>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const int>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const int&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, int>();
+  test_invalid_apply_result<NoExceptCallable<bool>, int&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const int>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const int&>();
+
+  test_invalid_apply_result_from_function<void(void*), void*>();
+  test_invalid_apply_result_from_function<void(void*), void*&>();
+  test_invalid_apply_result_from_function<void(void*), void* const>();
+  test_invalid_apply_result_from_function<void(void*), void* const&>();
+  test_invalid_apply_result_from_function<void(void*) noexcept, void*>();
+  test_invalid_apply_result_from_function<void(void*) noexcept, void*&>();
+  test_invalid_apply_result_from_function<void(void*) noexcept, void* const>();
+  test_invalid_apply_result_from_function<void(void*) noexcept, void* const&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, void*>();
+  test_invalid_apply_result<NoExceptCallable<bool>, void*&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, void* const>();
+  test_invalid_apply_result<NoExceptCallable<bool>, void* const&>();
+
+  // test plain aggregate
+  test_invalid_apply_result_from_function<void(), empty_aggregate>();
+  test_invalid_apply_result_from_function<void(), empty_aggregate&>();
+  test_invalid_apply_result_from_function<void(), const empty_aggregate>();
+  test_invalid_apply_result_from_function<void(), const empty_aggregate&>();
+  test_invalid_apply_result_from_function<void() noexcept, empty_aggregate>();
+  test_invalid_apply_result_from_function<void() noexcept, empty_aggregate&>();
+  test_invalid_apply_result_from_function<void() noexcept, const empty_aggregate>();
+  test_invalid_apply_result_from_function<void() noexcept, const empty_aggregate&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, empty_aggregate>();
+  test_invalid_apply_result<NoExceptCallable<bool>, empty_aggregate&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const empty_aggregate>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const empty_aggregate&>();
+
+  // test std::get-able class
+  test_invalid_apply_result_from_function<void(int), derived_from_tuple_int>();
+  test_invalid_apply_result_from_function<void(int), derived_from_tuple_int&>();
+  test_invalid_apply_result_from_function<void(int), const derived_from_tuple_int>();
+  test_invalid_apply_result_from_function<void(int), const derived_from_tuple_int&>();
+  test_invalid_apply_result_from_function<void(int) noexcept, derived_from_tuple_int>();
+  test_invalid_apply_result_from_function<void(int) noexcept, derived_from_tuple_int&>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const derived_from_tuple_int>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const derived_from_tuple_int&>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, derived_from_tuple_int>();
+  test_invalid_apply_result<NoExceptCallable<bool>, derived_from_tuple_int&>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const derived_from_tuple_int>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const derived_from_tuple_int&>();
+
+  // test built-in array
+  test_invalid_apply_result_from_function<void(int), int[1]>();
+  test_invalid_apply_result_from_function<void(int), int (&)[1]>();
+  test_invalid_apply_result_from_function<void(int), const int[1]>();
+  test_invalid_apply_result_from_function<void(int), const int (&)[1]>();
+  test_invalid_apply_result_from_function<void(int) noexcept, int[1]>();
+  test_invalid_apply_result_from_function<void(int) noexcept, int (&)[1]>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const int[1]>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const int (&)[1]>();
+
+  test_invalid_apply_result<NoExceptCallable<bool>, int[1]>();
+  test_invalid_apply_result<NoExceptCallable<bool>, int (&)[1]>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const int[1]>();
+  test_invalid_apply_result<NoExceptCallable<bool>, const int (&)[1]>();
+}
+
+void test_invalid_invocations() {
+  // test array
+  test_invalid_apply_result<void, std::array<int, 0>>();
+  test_invalid_apply_result<void*, std::array<int, 1>>();
+  test_invalid_apply_result<int, std::array<int, 2>>();
+  test_invalid_apply_result<int&, std::array<int, 3>>();
+  test_invalid_apply_result<int(int, int, int, int) const & noexcept, std::array<int, 4>>();
+
+  test_invalid_apply_result_from_function<void(int), std::array<int, 0>>();
+  test_invalid_apply_result_from_function<void(int), std::array<int, 0>&>();
+  test_invalid_apply_result_from_function<void(int), const std::array<int, 0>>();
+  test_invalid_apply_result_from_function<void(int), const std::array<int, 0>&>();
+  test_invalid_apply_result_from_function<void(int) noexcept, std::array<int, 0>>();
+  test_invalid_apply_result_from_function<void(int) noexcept, std::array<int, 0>&>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const std::array<int, 0>>();
+  test_invalid_apply_result_from_function<void(int) noexcept, const std::array<int, 0>&>();
+  test_invalid_apply_result_from_function<void(int, long), std::array<int, 1>>();
+  test_invalid_apply_result_from_function<void(int, long), std::array<int, 1>&>();
+  test_invalid_apply_result_from_function<void(int, long), const std::array<int, 1>>();
+  test_invalid_apply_result_from_function<void(int, long), const std::array<int, 1>&>();
+  test_invalid_apply_result_from_function<void(int, long) noexcept, std::array<int, 1>>();
+  test_invalid_apply_result_from_function<void(int, long) noexcept, std::array<int, 1>&>();
+  test_invalid_apply_result_from_function<void(int, long) noexcept, const std::array<int, 1>>();
+  test_invalid_apply_result_from_function<void(int, long) noexcept, const std::array<int, 1>&>();
+
+  // test complex
+  test_invalid_apply_result<void, std::complex<float>>();
+  test_invalid_apply_result<void*, std::complex<float>>();
+  test_invalid_apply_result<int, std::complex<float>>();
+  test_invalid_apply_result<int&, std::complex<float>>();
+  test_invalid_apply_result<void(float, float) const & noexcept, std::complex<float>>();
+
+  test_invalid_apply_result<void, std::complex<double>>();
+  test_invalid_apply_result<void*, std::complex<double>>();
+  test_invalid_apply_result<int, std::complex<double>>();
+  test_invalid_apply_result<int&, std::complex<double>>();
+  test_invalid_apply_result<void(double, double) const & noexcept, std::complex<double>>();
+
+  test_invalid_apply_result<void, std::complex<long double>>();
+  test_invalid_apply_result<void*, std::complex<long double>>();
+  test_invalid_apply_result<int, std::complex<long double>>();
+  test_invalid_apply_result<int&, std::complex<long double>>();
+  test_invalid_apply_result<void(long double, long double) const & noexcept, std::complex<long double>>();
+
+  test_invalid_apply_result_from_function<void(float), std::complex<float>>();
+  test_invalid_apply_result_from_function<void(float), std::complex<float>&>();
+  test_invalid_apply_result_from_function<void(float), const std::complex<float>>();
+  test_invalid_apply_result_from_function<void(float), const std::complex<float>&>();
+  test_invalid_apply_result_from_function<void(float) noexcept, std::complex<float>>();
+  test_invalid_apply_result_from_function<void(float) noexcept, std::complex<float>&>();
+  test_invalid_apply_result_from_function<void(float) noexcept, const std::complex<float>>();
+  test_invalid_apply_result_from_function<void(float) noexcept, const std::complex<float>&>();
+
+  test_invalid_apply_result_from_function<void(double), std::complex<double>>();
+  test_invalid_apply_result_from_function<void(double), std::complex<double>&>();
+  test_invalid_apply_result_from_function<void(double), const std::complex<double>>();
+  test_invalid_apply_result_from_function<void(double), const std::complex<double>&>();
+  test_invalid_apply_result_from_function<void(double) noexcept, std::complex<double>>();
+  test_invalid_apply_result_from_function<void(double) noexcept, std::complex<double>&>();
+  test_invalid_apply_result_from_function<void(double) noexcept, const std::complex<double>>();
+  test_invalid_apply_result_from_function<void(double) noexcept, const std::complex<double>&>();
+
+  test_invalid_apply_result_from_function<void(long double), std::complex<long double>>();
+  test_invalid_apply_result_from_function<void(long double), std::complex<long double>&>();
+  test_invalid_apply_result_from_function<void(long double), const std::complex<long double>>();
+  test_invalid_apply_result_from_function<void(long double), const std::complex<long double>&>();
+  test_invalid_apply_result_from_function<void(long double) noexcept, std::complex<long double>>();
+  test_invalid_apply_result_from_function<void(long double) noexcept, std::complex<long double>&>();
+  test_invalid_apply_result_from_function<void(long double) noexcept, const std::complex<long double>>();
+  test_invalid_apply_result_from_function<void(long double) noexcept, const std::complex<long double>&>();
+
+  // test subrange
+  using copyable_subrange = std::ranges::subrange<int*>;
+
+  test_invalid_apply_result<void, copyable_subrange>();
+  test_invalid_apply_result<void*, copyable_subrange>();
+  test_invalid_apply_result<int, copyable_subrange>();
+  test_invalid_apply_result<int&, copyable_subrange>();
+
+  test_invalid_apply_result_from_function<void(std::default_sentinel_t), copyable_subrange>();
+  test_invalid_apply_result_from_function<void(std::default_sentinel_t), copyable_subrange&>();
+  test_invalid_apply_result_from_function<int(std::default_sentinel_t), const copyable_subrange>();
+  test_invalid_apply_result_from_function<int(std::default_sentinel_t), const copyable_subrange&>();
+  test_invalid_apply_result_from_function<void(std::default_sentinel_t) noexcept, copyable_subrange>();
+  test_invalid_apply_result_from_function<void(std::default_sentinel_t) noexcept, copyable_subrange&>();
+  test_invalid_apply_result_from_function<int(std::default_sentinel_t) noexcept, const copyable_subrange>();
+  test_invalid_apply_result_from_function<int(std::default_sentinel_t) noexcept, const copyable_subrange&>();
+
+  using move_only_counted_iter = std::counted_iterator<cpp20_input_iterator<int*>>;
+  using move_only_subrange     = std::ranges::subrange<move_only_counted_iter, std::default_sentinel_t>;
+
+  test_invalid_apply_result<void, move_only_subrange>();
+  test_invalid_apply_result<void*, move_only_subrange>();
+  test_invalid_apply_result<int, move_only_subrange>();
+  test_invalid_apply_result<int&, move_only_subrange>();
+
+  test_invalid_apply_result_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                          move_only_subrange&>();
+  test_invalid_apply_result_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                          const move_only_subrange>();
+  test_invalid_apply_result_from_function<void(move_only_counted_iter&, std::default_sentinel_t),
+                                          const move_only_subrange&>();
+  test_invalid_apply_result_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                          move_only_subrange&>();
+  test_invalid_apply_result_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                          const move_only_subrange>();
+  test_invalid_apply_result_from_function<void(move_only_counted_iter&, std::default_sentinel_t) noexcept,
+                                          const move_only_subrange&>();
+
+  test_invalid_apply_result_from_function<void(std::default_sentinel_t), move_only_subrange>();
+  test_invalid_apply_result_from_function<void(std::default_sentinel_t), move_only_subrange&>();
+  test_invalid_apply_result_from_function<int(std::default_sentinel_t), const move_only_subrange>();
+  test_invalid_apply_result_from_function<int(std::default_sentinel_t), const move_only_subrange&>();
+  test_invalid_apply_result_from_function<void(std::default_sentinel_t) noexcept, move_only_subrange>();
+  test_invalid_apply_result_from_function<void(std::default_sentinel_t) noexcept, move_only_subrange&>();
+  test_invalid_apply_result_from_function<int(std::default_sentinel_t) noexcept, const move_only_subrange>();
+  test_invalid_apply_result_from_function<int(std::default_sentinel_t) noexcept, const move_only_subrange&>();
+
+  // test tuple
+  test_invalid_apply_result<void, std::tuple<>>();
+  test_invalid_apply_result<void*, std::tuple<>>();
+  test_invalid_apply_result<int, std::tuple<int>>();
+  test_invalid_apply_result<int&, std::tuple<int>>();
+  test_invalid_apply_result<int() const&, std::tuple<>>();
+  test_invalid_apply_result<int() const & noexcept, std::tuple<>>();
+
+  test_invalid_apply_result_from_function<int(), std::tuple<int>>();
+  test_invalid_apply_result_from_function<int(), std::tuple<int>&>();
+  test_invalid_apply_result_from_function<int(), const std::tuple<int>>();
+  test_invalid_apply_result_from_function<int(), const std::tuple<int>&>();
+  test_invalid_apply_result_from_function<int() noexcept, std::tuple<int>>();
+  test_invalid_apply_result_from_function<int() noexcept, std::tuple<int>&>();
+  test_invalid_apply_result_from_function<int() noexcept, const std::tuple<int>>();
+  test_invalid_apply_result_from_function<int() noexcept, const std::tuple<int>&>();
+
+  // test pair
+  test_invalid_apply_result<void, std::pair<int, long>>();
+  test_invalid_apply_result<void*, std::pair<int, long>>();
+  test_invalid_apply_result<int, std::pair<int, long>>();
+  test_invalid_apply_result<int&, std::pair<int, long>>();
+
+  test_invalid_apply_result<int(int, long) const&, std::pair<int, long>>();
+  test_invalid_apply_result<int(int, long) const & noexcept, std::pair<int, long>>();
+
+  test_invalid_apply_result_from_function<int(), std::pair<int, long>>();
+  test_invalid_apply_result_from_function<void(int, long, long long), std::pair<int, long>&>();
+  test_invalid_apply_result_from_function<int&(int), const std::pair<int, long>>();
+  test_invalid_apply_result_from_function<long&(int&, long&), const std::pair<int, long>&>();
+  test_invalid_apply_result_from_function<int() noexcept, std::pair<int, long>>();
+  test_invalid_apply_result_from_function<void(int, long, long long) noexcept, std::pair<int, long>&>();
+  test_invalid_apply_result_from_function<int&(int) noexcept, const std::pair<int, long>>();
+  test_invalid_apply_result_from_function<long&(int&, long&) noexcept, const std::pair<int, long>&>();
+}

>From a700737384e80debf94f113862e40ddbdda8f223 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 5 Aug 2025 19:23:39 +0800
Subject: [PATCH 2/3] Address review comments (except for tests)

---
 libcxx/docs/ReleaseNotes/22.rst                           | 2 --
 libcxx/include/{__type_traits => __tuple}/is_applicable.h | 0
 libcxx/include/module.modulemap.in                        | 8 ++++----
 libcxx/include/type_traits                                | 2 +-
 4 files changed, 5 insertions(+), 7 deletions(-)
 rename libcxx/include/{__type_traits => __tuple}/is_applicable.h (100%)

diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 05c375359a688..15bf46d44b07f 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -38,8 +38,6 @@ 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/include/__type_traits/is_applicable.h b/libcxx/include/__tuple/is_applicable.h
similarity index 100%
rename from libcxx/include/__type_traits/is_applicable.h
rename to libcxx/include/__tuple/is_applicable.h
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 6766960144a83..4ffbb35c8ede4 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -112,10 +112,6 @@ 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
@@ -2115,6 +2111,10 @@ module std [system] {
   module tuple {
     module find_index               { header "__tuple/find_index.h" }
     module ignore                   { header "__tuple/ignore.h" }
+    module is_applicable {
+      header "__tuple/is_applicable.h"
+      export std_core.type_traits.integral_constant
+    }
     module make_tuple_types         { header "__tuple/make_tuple_types.h" }
     module sfinae_helpers           { header "__tuple/sfinae_helpers.h" }
     module tuple_element            { header "__tuple/tuple_element.h" }
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index f8c3f744e07f4..9484be752af69 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -572,7 +572,7 @@ namespace std
 #  endif
 
 #  if _LIBCPP_STD_VER >= 26
-#    include <__type_traits/is_applicable.h>
+#    include <__tuple/is_applicable.h>
 #  endif
 
 #  include <version>

>From 12604b69dbade178eb31eebcb7b26c0d81e958d5 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 5 Aug 2025 21:54:51 +0800
Subject: [PATCH 3/3] Fix CMakeLists.txt

---
 libcxx/include/CMakeLists.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index a823a2f3a7a50..7955d94fbc63d 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -780,6 +780,7 @@ set(files
   __tree
   __tuple/find_index.h
   __tuple/ignore.h
+  __tuple/is_applicable.h
   __tuple/make_tuple_types.h
   __tuple/sfinae_helpers.h
   __tuple/tuple_element.h
@@ -819,7 +820,6 @@ 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



More information about the libcxx-commits mailing list