Skip to content

Commit 41918be

Browse files
[libc++] Implement the <type_traits> parts of P1317R2
Changes of `std::apply` are still blocked on related changes in P2165R4.
1 parent dcc71f2 commit 41918be

File tree

12 files changed

+2048
-2
lines changed

12 files changed

+2048
-2
lines changed

libcxx/docs/ReleaseNotes/22.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ What's New in Libc++ 22.0.0?
3838
Implemented Papers
3939
------------------
4040

41+
- P1317R2: Remove return type deduction in ``std::apply`` (`Github <https://github.com/llvm/llvm-project/issues/148183>`__)
42+
(Only components in ``<type_traits>`` are implemented.)
4143
- P2321R2: ``zip`` (`Github <https://github.com/llvm/llvm-project/issues/105169>`__) (The paper is partially implemented. ``zip_transform_view`` is implemented in this release)
4244

4345
Improvements and New Features

libcxx/docs/Status/Cxx2cPapers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,5 +155,5 @@
155155
"`P2781R9 <https://wg21.link/P2781R9>`__","``std::constant_wrapper``","2025-06 (Sofia)","","",""
156156
"`P3697R1 <https://wg21.link/P3697R1>`__","Minor additions to C++26 standard library hardening","2025-06 (Sofia)","","",""
157157
"`P3552R3 <https://wg21.link/P3552R3>`__","Add a Coroutine Task Type","2025-06 (Sofia)","","",""
158-
"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","","",""
158+
"`P1317R2 <https://wg21.link/P1317R2>`__","Remove return type deduction in ``std::apply``","2025-06 (Sofia)","|In Progress|","",""
159159
"","","","","",""

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,7 @@ set(files
819819
__type_traits/is_aggregate.h
820820
__type_traits/is_allocator.h
821821
__type_traits/is_always_bitcastable.h
822+
__type_traits/is_applicable.h
822823
__type_traits/is_arithmetic.h
823824
__type_traits/is_array.h
824825
__type_traits/is_assignable.h
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
10+
#define _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H
11+
12+
#include <__config>
13+
#include <__cstddef/size_t.h>
14+
#include <__fwd/get.h>
15+
#include <__tuple/tuple_like.h>
16+
#include <__tuple/tuple_size.h>
17+
#include <__type_traits/conjunction.h>
18+
#include <__type_traits/integral_constant.h>
19+
#include <__type_traits/invoke.h>
20+
#include <__type_traits/remove_reference.h>
21+
#include <__utility/declval.h>
22+
#include <__utility/integer_sequence.h>
23+
24+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
25+
# pragma GCC system_header
26+
#endif
27+
28+
_LIBCPP_BEGIN_NAMESPACE_STD
29+
30+
#if _LIBCPP_STD_VER >= 26
31+
32+
template <class _Fn, class _Tuple>
33+
struct __apply_result_disabled_base {};
34+
35+
template <class _Fn, class _Tuple, class _Tp>
36+
struct __apply_result_enabled_base {
37+
using type _LIBCPP_NODEBUG = _Tp;
38+
};
39+
40+
template <bool _Applicable, bool _Nothrow, class _Tp>
41+
struct __applicability_traits {
42+
static constexpr bool __applicable = true;
43+
static constexpr bool __nothrow_applicable = _Nothrow;
44+
45+
template <class _Fn, class _Tuple>
46+
using __base_type _LIBCPP_NODEBUG = __apply_result_enabled_base<_Fn, _Tuple, _Tp>;
47+
};
48+
49+
template <bool _Nothrow, class _Tp>
50+
struct __applicability_traits<false, _Nothrow, _Tp> {
51+
static_assert(!_Nothrow, "misspecified [_Applicable = false, _Nothrow = true]");
52+
static constexpr bool __applicable = false;
53+
static constexpr bool __nothrow_applicable = false;
54+
55+
template <class _Fn, class _Tuple>
56+
using __base_type _LIBCPP_NODEBUG = __apply_result_disabled_base<_Fn, _Tuple>;
57+
};
58+
59+
template <class _Fn, class _Tuple, size_t... _Is>
60+
concept __tuple_applicable_impl = requires(_Tuple&& __tuple) {
61+
[](auto&&...) {}(std::get<_Is>(static_cast<_Tuple &&>(__tuple))...);
62+
} && __is_invocable_v<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>;
63+
64+
template <class _Fn, class _Tuple, size_t... _Is>
65+
concept __tuple_nothrow_applicable_impl = requires(_Tuple&& __tuple) {
66+
{
67+
[](auto&&...) noexcept {}(std::get<_Is>(static_cast<_Tuple &&>(__tuple))...)
68+
} noexcept;
69+
} && __is_nothrow_invocable_v<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>;
70+
71+
template <class _Fn, class _Tuple>
72+
consteval auto __applicability_traits_of() {
73+
if constexpr (__tuple_like<_Tuple>)
74+
return []<size_t... _Is>(index_sequence<_Is...>) {
75+
if constexpr (__tuple_applicable_impl<_Fn, _Tuple, _Is...>) {
76+
return __applicability_traits<
77+
true,
78+
__tuple_nothrow_applicable_impl<_Fn, _Tuple, _Is...>,
79+
// FIXME: Use __invoke_result_y after merging https://github.com/llvm/llvm-project/pull/151028.
80+
typename __invoke_result<_Fn, decltype(std::get<_Is>(std::declval<_Tuple>()))...>::type>{};
81+
} else
82+
return __applicability_traits<false, false, void>{};
83+
}(make_index_sequence<tuple_size_v<remove_reference_t<_Tuple>>>{});
84+
else
85+
return __applicability_traits<false, false, void>{};
86+
}
87+
88+
template <class _Fn, class _Tuple>
89+
struct _LIBCPP_NO_SPECIALIZATIONS is_applicable
90+
: bool_constant<decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__applicable> {};
91+
92+
template <class _Fn, class _Tuple>
93+
struct _LIBCPP_NO_SPECIALIZATIONS is_nothrow_applicable
94+
: bool_constant<decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__nothrow_applicable> {};
95+
96+
template <class _Fn, class _Tuple>
97+
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_applicable_v =
98+
decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__applicable;
99+
100+
template <class _Fn, class _Tuple>
101+
_LIBCPP_NO_SPECIALIZATIONS inline constexpr bool is_nothrow_applicable_v =
102+
decltype(std::__applicability_traits_of<_Fn, _Tuple>())::__nothrow_applicable;
103+
104+
template <class _Fn, class _Tuple>
105+
struct _LIBCPP_NO_SPECIALIZATIONS apply_result
106+
: decltype(std::__applicability_traits_of<_Fn, _Tuple>())::template __base_type<_Fn, _Tuple> {};
107+
108+
template <class _Fn, class _Tuple>
109+
using apply_result_t = apply_result<_Fn, _Tuple>::type;
110+
111+
#endif // _LIBCPP_STD_VER >= 26
112+
113+
_LIBCPP_END_NAMESPACE_STD
114+
115+
#endif // _LIBCPP___TYPE_TRAITS_IS_APPLICABLE_H

libcxx/include/module.modulemap.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,10 @@ module std_core [system] {
112112
header "__type_traits/is_always_bitcastable.h"
113113
export std_core.type_traits.integral_constant
114114
}
115+
module is_applicable {
116+
header "__type_traits/is_applicable.h"
117+
export std_core.type_traits.integral_constant
118+
}
115119
module is_arithmetic {
116120
header "__type_traits/is_arithmetic.h"
117121
export std_core.type_traits.integral_constant

libcxx/include/type_traits

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,10 @@ namespace std
168168
template <class R, class Fn, class... ArgTypes>
169169
struct is_nothrow_invocable_r; // since C++17
170170
171+
template<class Fn, class Tuple> struct is_applicable; // since C++26
172+
template<class Fn, class Tuple>
173+
struct is_nothrow_applicable; // since C++26
174+
171175
// Alignment properties and transformations:
172176
template <class T> struct alignment_of;
173177
template <size_t Len, size_t Align = most_stringent_alignment_requirement>
@@ -183,6 +187,7 @@ namespace std
183187
struct result_of<Fn(ArgTypes...)>; // deprecated in C++17; removed in C++20
184188
template <class Fn, class... ArgTypes>
185189
struct invoke_result; // since C++17
190+
template<class Fn, class Tuple> struct apply_result; // since C++26
186191
187192
// const-volatile modifications:
188193
template <class T>
@@ -265,6 +270,9 @@ namespace std
265270
template <class Fn, class... ArgTypes>
266271
using invoke_result_t
267272
= typename invoke_result<Fn, ArgTypes...>::type; // since C++17
273+
template <class Fn, class... ArgTypes>
274+
using apply_result_t
275+
= typename invoke_result<Fn, ArgTypes...>::type; // since C++26
268276
269277
template <class...>
270278
using void_t = void; // since C++17
@@ -442,6 +450,10 @@ namespace std
442450
= is_nothrow_invocable<Fn, ArgTypes...>::value; // since C++17
443451
template <class R, class Fn, class... ArgTypes> inline constexpr bool is_nothrow_invocable_r_v
444452
= is_nothrow_invocable_r<R, Fn, ArgTypes...>::value; // since C++17
453+
template<class Fn, class Tuple> constexpr bool is_applicable_v
454+
= is_applicable<Fn, Tuple>::value; // since C++26
455+
template<class Fn, class Tuple> constexpr bool is_nothrow_applicable_v
456+
= is_nothrow_applicable<Fn, Tuple>::value; // since C++26
445457
446458
// [meta.logical], logical operator traits:
447459
template<class... B> struct conjunction; // since C++17
@@ -559,6 +571,10 @@ namespace std
559571
# include <__type_traits/reference_converts_from_temporary.h>
560572
# endif
561573

574+
# if _LIBCPP_STD_VER >= 26
575+
# include <__type_traits/is_applicable.h>
576+
# endif
577+
562578
# include <version>
563579

564580
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)

libcxx/modules/std/type_traits.inc

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ export namespace std {
121121
using std::rank;
122122

123123
// [meta.rel], type relations
124+
#if _LIBCPP_STD_VER >= 26
125+
using std::is_applicable;
126+
#endif
124127
using std::is_base_of;
125128
#if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_virtual_base_of)
126129
using std::is_virtual_base_of;
@@ -134,6 +137,9 @@ export namespace std {
134137
using std::is_invocable;
135138
using std::is_invocable_r;
136139

140+
#if _LIBCPP_STD_VER >= 26
141+
using std::is_nothrow_applicable;
142+
#endif
137143
using std::is_nothrow_invocable;
138144
using std::is_nothrow_invocable_r;
139145

@@ -183,6 +189,9 @@ export namespace std {
183189
using std::remove_pointer_t;
184190

185191
// [meta.trans.other], other transformations
192+
#if _LIBCPP_STD_VER >= 26
193+
using std::apply_result;
194+
#endif
186195
using std::basic_common_reference;
187196
using std::common_reference;
188197
using std::common_type;
@@ -196,6 +205,9 @@ export namespace std {
196205
using std::unwrap_ref_decay;
197206
using std::unwrap_reference;
198207

208+
#if _LIBCPP_STD_VER >= 26
209+
using std::apply_result_t;
210+
#endif
199211
using std::common_reference_t;
200212
using std::common_type_t;
201213
using std::conditional_t;
@@ -305,6 +317,9 @@ export namespace std {
305317
using std::rank_v;
306318

307319
// [meta.rel], type relations
320+
#if _LIBCPP_STD_VER >= 26
321+
using std::is_applicable_v;
322+
#endif
308323
using std::is_base_of_v;
309324
#if _LIBCPP_STD_VER >= 26 && __has_builtin(__builtin_is_virtual_base_of)
310325
using std::is_virtual_base_of_v;
@@ -313,6 +328,9 @@ export namespace std {
313328
using std::is_invocable_r_v;
314329
using std::is_invocable_v;
315330
// using std::is_layout_compatible_v;
331+
#if _LIBCPP_STD_VER >= 26
332+
using std::is_nothrow_applicable_v;
333+
#endif
316334
using std::is_nothrow_convertible_v;
317335
using std::is_nothrow_invocable_r_v;
318336
using std::is_nothrow_invocable_v;

libcxx/test/libcxx/type_traits/no_specializations.verify.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,11 @@ SPECIALIZE_TRAIT(unwrap_reference); // expected-error {{cannot be specialized}}
5353
SPECIALIZE_TRAIT(unwrap_ref_decay); // expected-error {{cannot be specialized}}
5454
# endif
5555

56+
# if TEST_STD_VER >= 26
57+
template <>
58+
struct std::apply_result<S, S>; // expected-error {{cannot be specialized}}
59+
# endif
60+
5661
# undef SPECIALIZE_TRAIT
5762
# define SPECIALIZE_UTT(Trait) \
5863
template <> \
@@ -165,7 +170,9 @@ SPECIALIZE_BTT(reference_converts_from_temporary); // expected-error 2 {{cannot
165170
# endif
166171

167172
# if TEST_STD_VER >= 26
168-
SPECIALIZE_BTT(is_virtual_base_of); // expected-error 2 {{cannot be specialized}}
173+
SPECIALIZE_BTT(is_applicable); // expected-error 2 {{cannot be specialized}}
174+
SPECIALIZE_BTT(is_nothrow_applicable); // expected-error 2 {{cannot be specialized}}
175+
SPECIALIZE_BTT(is_virtual_base_of); // expected-error 2 {{cannot be specialized}}
169176
# endif
170177

171178
# undef SPECIALIZE_UTT

libcxx/test/std/utilities/meta/derived_from_integral_constant.compile.pass.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,6 @@ static_assert(std::is_base_of<std::false_type, std::is_scoped_enum<int>>::value,
113113
# if defined(__cpp_lib_is_virtual_base_of) && __cpp_lib_is_virtual_base_of >= 202406L
114114
static_assert(std::is_base_of<std::false_type, std::is_virtual_base_of<int, int>>::value, "");
115115
# endif
116+
static_assert(std::is_base_of<std::false_type, std::is_applicable<int, int>>::value, "");
117+
static_assert(std::is_base_of<std::false_type, std::is_nothrow_applicable<int, int>>::value, "");
116118
#endif

0 commit comments

Comments
 (0)