-
Notifications
You must be signed in to change notification settings - Fork 14.7k
[libc++] Implement the <type_traits>
parts of P1317R2
#151480
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-libcxx Author: A. Jiang (frederick-vs-ja) ChangesChanges of Patch is 136.46 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/151480.diff 12 Files Affected:
diff --git a/libcxx/docs/ReleaseNotes/22.rst b/libcxx/docs/ReleaseNotes/22.rst
index 15bf46d44b07f..05c375359a688 100644
--- a/libcxx/docs/ReleaseNotes/22.rst
+++ b/libcxx/docs/ReleaseNotes/22.rst
@@ -38,6 +38,8 @@ What's New in Libc++ 22.0.0?
Implemented Papers
------------------
+- P1317R2: Remove return type deduction in ``std::apply`` (`Github <https://github.com/llvm/llvm-project/issues/148183>`__)
+ (Only components in ``<type_traits>`` are implemented.)
- P2321R2: ``zip`` (`Github <https://github.com/llvm/llvm-project/issues/105169>`__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release)
Improvements and New Features
diff --git a/libcxx/docs/Status/Cxx2cPapers.csv b/libcxx/docs/Status/Cxx2cPapers.csv
index febb0c176f9c4..99be92021434e 100644
--- a/libcxx/docs/Status/Cxx2cPapers.csv
+++ b/libcxx/docs/Status/Cxx2cPapers.csv
@@ -155,5 +155,5 @@
"`P2781R9 <https://wg21.link/P2781R9>`__","``std::constant_wrapper``","2025-06 (Sofia)","","",""
"`P3697R1 <https://wg21.link/P3697R1>`__","Minor additions to C++26 standard library hardening","2025-06 (Sofia)","","",""
"`P3552R3 <https://wg21.link/P3552R3>`__","Add a Coroutine Task Type","2025-06 (Sofia)","","",""
-"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","","",""
+"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","|In Progress|","",""
"","","","","",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 51444ec668e2b..a823a2f3a7a50 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -819,6 +819,7 @@ set(files
__type_traits/is_aggregate.h
__type_traits/is_allocator.h
__type_traits/is_always_bitcastable.h
+ __type_traits/is_applicable.h
__type_traits/is_arithmetic.h
__type_traits/is_array.h
__type_traits/is_assignable.h
diff --git a/libcxx/include/__type_traits/is_applicable.h b/libcxx/include/__type_traits/is_applicable.h
new file mode 100644
index 0000000000000..fc97a0c4a9ad1
--- /dev/null
+++ b/libcxx/include/__type_traits/is_applicable.h
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
+#define _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
+
+#include <__config>
+#include <__cstddef/size_t.h>
+#include <__functional/invoke.h>
+#include <__fwd/get.h>
+#include <__tuple/tuple_like.h>
+#include <__tuple/tuple_size.h>
+#include <__type_traits/conjunction.h>
+#include <__type_traits/integral_constant.h>
+#include <__type_traits/remove_reference.h>
+#include <__utility/declval.h>
+#include <__utility/integer_sequence.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 26
+
+template <class _Fn, class _Tuple>
+struct __apply_result_disabled_base {};
+
+template <class _Fn, class _Tuple, class _Tp>
+struct __apply_result_enabled_base {
+ using type _LIBCPP_NODEBUG = _Tp;
+};
+
+template <bool _Applicable, bool _Nothrow, class _Tp>
+struct __applicability_traits {
+ static constexpr bool __applicable = true;
+ static constexpr bool __nothrow_applicable = _Nothrow;
+
+ template <class _Fn, class _Tuple>
+ using __base_type _LIBCPP_NODEBUG = __apply_result_enabled_base<_Fn, _Tuple, _Tp>;
+};
+
+template <bool _Nothrow, class _Tp>
+struct __applicability_traits<false, _Nothrow, _Tp> {
+ static_assert(!_Nothrow, "misspecified [_Applicable = false, _Nothrow = true]");
+ static constexpr bool __applicable = false;
+ static constexpr bool __nothrow_applicable = false;
+
+ template <class _Fn, class _Tuple>
+ using __base_type _LIBCPP_NODEBUG = __apply_result_disabled_base<_Fn, _Tuple>;
+};
+
+template <class _Fn, class _Tuple>
+consteval auto __applicability_traits_of() {
+ if constexpr (__tuple_like<_Tuple>)
+ return []<size_t... _Is>(index_sequence<_Is...>) {
+ constexpr bool __is_tuple_applicable = requires(_Fn&& __fn, _Tuple&& __tuple) {
+ std::invoke(static_cast<_Fn&&>(__fn), std::get<_Is>(static_cast<_Tuple&&>(__tuple))...);
+ };
+ if constexpr (__is_tuple_applicable)
+ return __applicability_traits<
+ true,
+ noexcept(std::invoke(std::declval<_Fn>(), std::get<_Is>(std::declval<_Tuple>())...)),
+ decltype(std::invoke(std::declval<_Fn>(), std::get<_Is>(std::declval<_Tuple>())...))>{};
+ else
+ return __applicability_traits<false, false, void>{};
+ }(make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{});
+ else
+ return __applicability_traits<false, false, void>{};
+}
+
+template <class _Fn, class _Tuple>
+struct _LIBCPP_NO_SPECIALIZATIONS is_applicable
+ : bool_constant<decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__applicable> {};
+
+template <class _Fn, class _Tuple>
+struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_applicable
+ : bool_constant<decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__nothrow_applicable> {};
+
+template <class _Fn, class _Tuple>
+_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_applicable_v =
+ decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__applicable;
+
+template <class _Fn, class _Tuple>
+_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_applicable_v =
+ decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__nothrow_applicable;
+
+template <class _Fn, class _Tuple>
+struct _LIBCPP_NO_SPECIALIZATIONS apply_result
+ : decltype(std::__applicability_traits_of<_Fn, _Tuple>())::template __base_type<_Fn, _Tuple> {};
+
+template <class _Fn, class _Tuple>
+using apply_result_t = apply_result<_Fn, _Tuple>::type;
+
+#endif // _LIBCPP_STD_VER >= 26
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in
index 5857a83b5fe14..6766960144a83 100644
--- a/libcxx/include/module.modulemap.in
+++ b/libcxx/include/module.modulemap.in
@@ -112,6 +112,10 @@ module std_core [system] {
header "__type_traits/is_always_bitcastable.h"
export std_core.type_traits.integral_constant
}
+ module is_applicable {
+ header "__type_traits/is_applicable.h"
+ export std_core.type_traits.integral_constant
+ }
module is_arithmetic {
header "__type_traits/is_arithmetic.h"
export std_core.type_traits.integral_constant
diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits
index a6e0c1867566b..f8c3f744e07f4 100644
--- a/libcxx/include/type_traits
+++ b/libcxx/include/type_traits
@@ -168,6 +168,10 @@ namespace std
template <class R, class Fn, class... ArgTypes>
struct is_nothrow_invocable_r; // since C++17
+ template<class Fn, class Tuple> struct is_applicable; // since C++26
+ template<class Fn, class Tuple>
+ struct is_nothrow_applicable; // since C++26
+
// Alignment properties and transformations:
template <class T> struct alignment_of;
template <size_t Len, size_t Align = most_stringent_alignment_requirement>
@@ -183,6 +187,7 @@ namespace std
struct result_of<Fn(ArgTypes...)>; // deprecated in C++17; removed in C++20
template <class Fn, class... ArgTypes>
struct invoke_result; // since C++17
+ template<class Fn, class Tuple> struct apply_result; // since C++26
// const-volatile modifications:
template <class T>
@@ -265,6 +270,9 @@ namespace std
template <class Fn, class... ArgTypes>
using invoke_result_t
= typename invoke_result<Fn, ArgTypes...>::type; // since C++17
+ template <class Fn, class... ArgTypes>
+ using apply_result_t
+ = typename invoke_result<Fn, ArgTypes...>::type; // since C++26
template <class...>
using void_t = void; // since C++17
@@ -442,6 +450,10 @@ namespace std
= is_nothrow_invocable<Fn, ArgTypes...>::value; // since C++17
template <class R, class Fn, class... ArgTypes> inline constexpr bool is_nothrow_invocable_r_v
= is_nothrow_invocable_r<R, Fn, ArgTypes...>::value; // since C++17
+ template<class Fn, class Tuple> constexpr bool is_applicable_v
+ = is_applicable<Fn, Tuple>::value; // since C++26
+ template<class Fn, class Tuple> constexpr bool is_nothrow_applicable_v
+ = is_nothrow_applicable<Fn, Tuple>::value; // since C++26
// [meta.logical], logical operator traits:
template<class... B> struct conjunction; // since C++17
@@ -559,6 +571,10 @@ namespace std
# include <__type_traits/reference_converts_from_temporary.h>
# endif
+# if _LIBCPP_STD_VER >= 26
+# include <__type_traits/is_applicable.h>
+# endif
+
# include <version>
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
diff --git a/libcxx/modules/std/type_traits.inc b/libcxx/modules/std/type_traits.inc
index 6823c86ed153b..0ad2bb4bea27f 100644
--- a/libcxx/modules/std/type_traits.inc
+++ b/libcxx/modules/std/type_traits.inc
@@ -121,6 +121,9 @@ export namespace std {
using std::rank;
// [meta.rel], type relations
+#if _LIBCPP_STD_VER >= 26
+ using std::is_applicable;
+#endif
using std::is_base_of;
#if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_virtual_base_of)
using std::is_virtual_base_of;
@@ -134,6 +137,9 @@ export namespace std {
using std::is_invocable;
using std::is_invocable_r;
+#if _LIBCPP_STD_VER >= 26
+ using std::is_nothrow_applicable;
+#endif
using std::is_nothrow_invocable;
using std::is_nothrow_invocable_r;
@@ -183,6 +189,9 @@ export namespace std {
using std::remove_pointer_t;
// [meta.trans.other], other transformations
+#if _LIBCPP_STD_VER >= 26
+ using std::apply_result;
+#endif
using std::basic_common_reference;
using std::common_reference;
using std::common_type;
@@ -196,6 +205,9 @@ export namespace std {
using std::unwrap_ref_decay;
using std::unwrap_reference;
+#if _LIBCPP_STD_VER >= 26
+ using std::apply_result_t;
+#endif
using std::common_reference_t;
using std::common_type_t;
using std::conditional_t;
@@ -305,6 +317,9 @@ export namespace std {
using std::rank_v;
// [meta.rel], type relations
+#if _LIBCPP_STD_VER >= 26
+ using std::is_applicable_v;
+#endif
using std::is_base_of_v;
#if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_virtual_base_of)
using std::is_virtual_base_of_v;
@@ -313,6 +328,9 @@ export namespace std {
using std::is_invocable_r_v;
using std::is_invocable_v;
// using std::is_layout_compatible_v;
+#if _LIBCPP_STD_VER >= 26
+ using std::is_nothrow_applicable_v;
+#endif
using std::is_nothrow_convertible_v;
using std::is_nothrow_invocable_r_v;
using std::is_nothrow_invocable_v;
diff --git a/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp b/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
index 897ae89365014..b76a75a3b1584 100644
--- a/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
+++ b/libcxx/test/libcxx/type_traits/no_specializations.verify.cpp
@@ -53,6 +53,11 @@ SPECIALIZE_TRAIT(unwrap_reference); // expected-error {{cannot be specialized}}
SPECIALIZE_TRAIT(unwrap_ref_decay); // expected-error {{cannot be specialized}}
# endif
+# if TEST_STD_VER >= 26
+template <>
+struct std::apply_result<S, S>; // expected-error {{cannot be specialized}}
+# endif
+
# undef SPECIALIZE_TRAIT
# define SPECIALIZE_UTT(Trait) \
template <> \
@@ -165,7 +170,9 @@ SPECIALIZE_BTT(reference_converts_from_temporary); // expected-error 2 {{cannot
# endif
# if TEST_STD_VER >= 26
-SPECIALIZE_BTT(is_virtual_base_of); // expected-error 2 {{cannot be specialized}}
+SPECIALIZE_BTT(is_applicable); // expected-error 2 {{cannot be specialized}}
+SPECIALIZE_BTT(is_nothrow_applicable); // expected-error 2 {{cannot be specialized}}
+SPECIALIZE_BTT(is_virtual_base_of); // expected-error 2 {{cannot be specialized}}
# endif
# undef SPECIALIZE_UTT
diff --git a/libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp b/libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp
index 3db7a214b27bd..eb021f5840c6c 100644
--- a/libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp
+++ b/libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp
@@ -113,4 +113,6 @@ static_assert(std::is_base_of<std::false_type, std::is_scoped_enum<int>>::value,
# if defined(__cpp_lib_is_virtual_base_of) && __cpp_lib_is_virtual_base_of >= 202406L
static_assert(std::is_base_of<std::false_type, std::is_virtual_base_of<int, int>>::value, "");
# endif
+static_assert(std::is_base_of<std::false_type, std::is_applicable<int, int>>::value, "");
+static_assert(std::is_base_of<std::false_type, std::is_nothrow_applicable<int, int>>::value, "");
#endif
diff --git a/libcxx/test/std/utilities/meta/meta.rel/is_applicable.compile.pass.cpp b/libcxx/test/std/utilities/meta/meta.rel/is_applicable.compile.pass.cpp
new file mode 100644
index 0000000000000..bd8531c02a2e0
--- /dev/null
+++ b/libcxx/test/std/utilities/meta/meta.rel/is_applicable.compile.pass.cpp
@@ -0,0 +1,598 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: std-at-least-c++26
+
+// <type_traits>
+
+// template<class Fn, class Tuple> struct is_applicable;
+
+// template<class Fn, class Tuple>
+// constexpr bool is_applicable_v = is_applicable<T, U>::value;
+
+#include <cassert>
+#include <cstddef>
+#include <array>
+#include <complex>
+#include <ranges>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#include "callable_types.h"
+#include "test_iterators.h"
+
+struct empty_aggregate {};
+
+struct derived_from_tuple_int : std::tuple<int> {};
+
+template <>
+struct std::tuple_size<derived_from_tuple_int> : std::integral_constant<std::size_t, 1> {};
+
+template <std::size_t I>
+ requires(I < 1)
+struct std::tuple_element<I, derived_from_tuple_int> {
+ using type = std::tuple_element_t<I, std::tuple<int>>;
+};
+
+template <class Fn, class Tuple, bool Expected>
+void test_is_applicable() {
+ static_assert(std::is_applicable<Fn, Tuple>::value == Expected);
+ static_assert(std::is_applicable_v<Fn, Tuple> == Expected);
+
+ static_assert(std::is_base_of_v<std::bool_constant<Expected>, std::is_applicable<Fn, Tuple>>);
+ static_assert(std::is_convertible_v<std::is_applicable<Fn, Tuple>*, std::bool_constant<Expected>*>);
+}
+
+template <class Func, class Tuple, bool Expected>
+void test_is_applicable_from_function() {
+ static_assert(std::is_function_v<Func>);
+
+ test_is_applicable<Func, Tuple, Expected>();
+ test_is_applicable<Func&, Tuple, Expected>();
+
+ test_is_applicable<Func*, Tuple, Expected>();
+ test_is_applicable<Func*&, Tuple, Expected>();
+ test_is_applicable<Func* const, Tuple, Expected>();
+ test_is_applicable<Func* const&, Tuple, Expected>();
+ test_is_applicable<Func* volatile, Tuple, Expected>();
+ test_is_applicable<Func* volatile&, Tuple, Expected>();
+ test_is_applicable<Func* const volatile, Tuple, Expected>();
+ test_is_applicable<Func* const volatile&, Tuple, Expected>();
+}
+
+void test_valid() {
+ // test array
+ test_is_applicable_from_function<int(), std::array<int, 0>, true>();
+ test_is_applicable_from_function<int(), std::array<long, 0>&, true>();
+ test_is_applicable_from_function<int(), const std::array<char, 0>, true>();
+ test_is_applicable_from_function<int(), const std::array<std::array<int, 1>, 0>&, true>();
+ test_is_applicable_from_function<int() noexcept, std::array<int, 0>, true>();
+ test_is_applicable_from_function<int() noexcept, std::array<long, 0>&, true>();
+ test_is_applicable_from_function<int() noexcept, const std::array<char, 0>, true>();
+ test_is_applicable_from_function<int() noexcept, const std::array<std::array<int, 1>, 0>&, true>();
+
+ test_is_applicable_from_function<int(long), std::array<int, 1>, true>();
+ test_is_applicable_from_function<int&(int), std::array<long, 1>&, true>();
+ test_is_applicable_from_function<const int && (float), const std::array<double, 1>, true>();
+ test_is_applicable_from_function<void(double), const std::array<char, 1>&, true>();
+ test_is_applicable_from_function<int(long) noexcept, std::array<int, 1>, true>();
+ test_is_applicable_from_function<int&(int) noexcept, std::array<long, 1>&, true>();
+ test_is_applicable_from_function<const int && (float) noexcept, const std::array<double, 1>, true>();
+ test_is_applicable_from_function<void(double) noexcept, const std::array<char, 1>&, true>();
+
+ test_is_applicable_from_function<int(long, int), std::array<int, 2>, true>();
+ test_is_applicable_from_function<int&(long, int), std::array<int, 2>&, true>();
+ test_is_applicable_from_function<const int && (long, int), const std::array<int, 2>, true>();
+ test_is_applicable_from_function<void(long, int), const std::array<int, 2>&, true>();
+ test_is_applicable_from_function<int(long, int) noexcept, std::array<int, 2>, true>();
+ test_is_applicable_from_function<int&(long, int) noexcept, std::array<int, 2>&, true>();
+ test_is_applicable_from_function<const int && (long, int) noexcept, const std::array<int, 2>, true>();
+ test_is_applicable_from_function<void(long, int) noexcept, const std::array<int, 2>&, true>();
+
+ test_is_applicable<ConstCallable<bool>, std::array<int, 0>, true>();
+ test_is_applicable<ConstCallable<bool>, std::array<int, 1>&, true>();
+ test_is_applicable<ConstCallable<bool>, const std::array<int, 2>, true>();
+ test_is_applicable<ConstCallable<bool>, const std::array<int, 3>&, true>();
+
+ test_is_applicable<NoExceptCallable<bool>, std::array<int, 0>, true>();
+ test_is_applicable<NoExceptCallable<bool>, std::array<int, 1>&, true>();
+ test_is_applicable<NoExceptCallable<bool>, const std::array<int, 2>, true>();
+ test_is_applicable<NoExceptCallable<bool>, const std::array<int, 3>&, true>();
+
+ // test complex
+ test_is_applicable_from_function<float(float, float), std::complex<float>, true>();
+ test_is_applicable_from_function<float(float&, float&), std::complex<float>&, true>();
+ test_is_applicable_from_function<void(float, float), const std::complex<float>, true>();
+ test_is_applicable_from_function<double(float, float), const std::complex<float>&, true>();
+ test_is_applicable_from_function<float(float, float) noexcept, std::complex<float>, true>();
+ test_is_applicable_from_function<float(float&, float&) noexcept, std::complex<float>&, true>();
+ test_is_applicable_from_function<void(float, float) noexcept, const std::complex<float>, true>();
+ test_is_applicable_from_function<double(float, float) noexcept, const std::complex<float>&, true>();
+
+ test_is_applicable<ConstCallable<bool>, std::complex<float>, true>();
+ test_is_applicable<ConstCallable<bool>, std::complex<float>&, true>();
+ test_is_applicable<ConstCallable<bool>, const std::complex<float>, true>();
+ test_is_applicable<ConstCallable<bool>, const std::complex<float>&, true>();
+
+ test_is_applicable<NoExceptCallable<bool>, std::complex<float>, true>();
+ test_is_applicable<NoExceptCallable<bool>, std::complex<float>&, true>();
+ test_is_applicable<NoExceptCallable<bool>, const std::complex<float>, true>();
+ test_is_applicable<NoExceptCallable<bool>, const std::complex<float>&, true...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
926656e
to
3f8ae7d
Compare
#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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These includes seemingly heavily break module builds. I guess we need to expand the std_core
module a lot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a bit problematic. I almost wonder if we should put this new stuff under __tuple
instead? It clearly belongs to type_traits
, but putting it inside __tuple
would simplify things from a modularization perspective.
3f8ae7d
to
41918be
Compare
Changes of `std::apply` are still blocked on related changes in P2165R4.
41918be
to
6cf03e7
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have some minor comments, this basically looks good but I have some maintainability concerns with the current tests!
#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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a bit problematic. I almost wonder if we should put this new stuff under __tuple
instead? It clearly belongs to type_traits
, but putting it inside __tuple
would simplify things from a modularization perspective.
} | ||
|
||
void test_valid() { | ||
// test array |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like a lot of these tests are generated? Would there be a way to share this between the three test files we're adding in this patch, since there seems to be a lot of redundancy? I'm a bit worried about the maintainability of these tests as written right now (but am quite happy about their apparent exhaustiveness).
Changes of
std::apply
are still blocked on related changes in P2165R4. Towards #148183.