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 | // UNSUPPORTED: c++03, c++11, c++14 |
10 | |
11 | // type_traits |
12 | |
13 | // is_invocable |
14 | |
15 | // Most testing of is_invocable is done within the [meta.trans.other] result_of |
16 | // tests. |
17 | |
18 | // Fn and all types in the template parameter pack ArgTypes shall be |
19 | // complete types, cv void, or arrays of unknown bound. |
20 | |
21 | #include <type_traits> |
22 | #include <functional> |
23 | #include <memory> |
24 | #include <vector> |
25 | |
26 | #include "test_macros.h" |
27 | |
28 | struct Tag {}; |
29 | struct DerFromTag : Tag {}; |
30 | |
31 | struct Implicit { |
32 | Implicit(int) {} |
33 | }; |
34 | |
35 | struct Explicit { |
36 | explicit Explicit(int) {} |
37 | }; |
38 | |
39 | struct NotCallableWithInt { |
40 | int operator()(int) = delete; |
41 | int operator()(Tag) { return 42; } |
42 | }; |
43 | |
44 | struct Sink { |
45 | template <class ...Args> |
46 | void operator()(Args&&...) const {} |
47 | }; |
48 | |
49 | int main(int, char**) { |
50 | using AbominableFunc = void(...) const; |
51 | |
52 | // Non-callable things |
53 | { |
54 | static_assert(!std::is_invocable<void>::value, "" ); |
55 | static_assert(!std::is_invocable<const void>::value, "" ); |
56 | static_assert(!std::is_invocable<volatile void>::value, "" ); |
57 | static_assert(!std::is_invocable<const volatile void>::value, "" ); |
58 | static_assert(!std::is_invocable<std::nullptr_t>::value, "" ); |
59 | static_assert(!std::is_invocable<int>::value, "" ); |
60 | static_assert(!std::is_invocable<double>::value, "" ); |
61 | |
62 | static_assert(!std::is_invocable<int[]>::value, "" ); |
63 | static_assert(!std::is_invocable<int[3]>::value, "" ); |
64 | |
65 | static_assert(!std::is_invocable<int*>::value, "" ); |
66 | static_assert(!std::is_invocable<const int*>::value, "" ); |
67 | static_assert(!std::is_invocable<int const*>::value, "" ); |
68 | |
69 | static_assert(!std::is_invocable<int&>::value, "" ); |
70 | static_assert(!std::is_invocable<const int&>::value, "" ); |
71 | static_assert(!std::is_invocable<int&&>::value, "" ); |
72 | |
73 | static_assert(!std::is_invocable<std::vector<int> >::value, "" ); |
74 | static_assert(!std::is_invocable<std::vector<int*> >::value, "" ); |
75 | static_assert(!std::is_invocable<std::vector<int**> >::value, "" ); |
76 | |
77 | static_assert(!std::is_invocable<AbominableFunc>::value, "" ); |
78 | |
79 | // with parameters |
80 | static_assert(!std::is_invocable<int, int>::value, "" ); |
81 | static_assert(!std::is_invocable<int, double, float>::value, "" ); |
82 | static_assert(!std::is_invocable<int, char, float, double>::value, "" ); |
83 | static_assert(!std::is_invocable<Sink, AbominableFunc>::value, "" ); |
84 | static_assert(!std::is_invocable<Sink, void>::value, "" ); |
85 | static_assert(!std::is_invocable<Sink, const volatile void>::value, |
86 | "" ); |
87 | |
88 | |
89 | static_assert(!std::is_invocable_r<int, void>::value, "" ); |
90 | static_assert(!std::is_invocable_r<int, const void>::value, "" ); |
91 | static_assert(!std::is_invocable_r<int, volatile void>::value, "" ); |
92 | static_assert(!std::is_invocable_r<int, const volatile void>::value, "" ); |
93 | static_assert(!std::is_invocable_r<int, std::nullptr_t>::value, "" ); |
94 | static_assert(!std::is_invocable_r<int, int>::value, "" ); |
95 | static_assert(!std::is_invocable_r<int, double>::value, "" ); |
96 | |
97 | static_assert(!std::is_invocable_r<int, int[]>::value, "" ); |
98 | static_assert(!std::is_invocable_r<int, int[3]>::value, "" ); |
99 | |
100 | static_assert(!std::is_invocable_r<int, int*>::value, "" ); |
101 | static_assert(!std::is_invocable_r<int, const int*>::value, "" ); |
102 | static_assert(!std::is_invocable_r<int, int const*>::value, "" ); |
103 | |
104 | static_assert(!std::is_invocable_r<int, int&>::value, "" ); |
105 | static_assert(!std::is_invocable_r<int, const int&>::value, "" ); |
106 | static_assert(!std::is_invocable_r<int, int&&>::value, "" ); |
107 | |
108 | static_assert(!std::is_invocable_r<int, std::vector<int> >::value, "" ); |
109 | static_assert(!std::is_invocable_r<int, std::vector<int*> >::value, "" ); |
110 | static_assert(!std::is_invocable_r<int, std::vector<int**> >::value, "" ); |
111 | static_assert(!std::is_invocable_r<void, AbominableFunc>::value, "" ); |
112 | |
113 | // with parameters |
114 | static_assert(!std::is_invocable_r<int, int, int>::value, "" ); |
115 | static_assert(!std::is_invocable_r<int, int, double, float>::value, "" ); |
116 | static_assert(!std::is_invocable_r<int, int, char, float, double>::value, |
117 | "" ); |
118 | static_assert(!std::is_invocable_r<void, Sink, AbominableFunc>::value, "" ); |
119 | static_assert(!std::is_invocable_r<void, Sink, void>::value, "" ); |
120 | static_assert(!std::is_invocable_r<void, Sink, const volatile void>::value, |
121 | "" ); |
122 | } |
123 | { |
124 | using Fn = int (Tag::*)(int); |
125 | using RFn = int (Tag::*)(int)&&; |
126 | // INVOKE bullet 1, 2 and 3 |
127 | { |
128 | // Bullet 1 |
129 | static_assert(std::is_invocable<Fn, Tag&, int>::value, "" ); |
130 | static_assert(std::is_invocable<Fn, DerFromTag&, int>::value, "" ); |
131 | static_assert(std::is_invocable<RFn, Tag&&, int>::value, "" ); |
132 | static_assert(!std::is_invocable<RFn, Tag&, int>::value, "" ); |
133 | static_assert(!std::is_invocable<Fn, Tag&>::value, "" ); |
134 | static_assert(!std::is_invocable<Fn, Tag const&, int>::value, "" ); |
135 | } |
136 | { |
137 | // Bullet 2 |
138 | using T = std::reference_wrapper<Tag>; |
139 | using DT = std::reference_wrapper<DerFromTag>; |
140 | using CT = std::reference_wrapper<const Tag>; |
141 | static_assert(std::is_invocable<Fn, T&, int>::value, "" ); |
142 | static_assert(std::is_invocable<Fn, DT&, int>::value, "" ); |
143 | static_assert(std::is_invocable<Fn, const T&, int>::value, "" ); |
144 | static_assert(std::is_invocable<Fn, T&&, int>::value, "" ); |
145 | static_assert(!std::is_invocable<Fn, CT&, int>::value, "" ); |
146 | static_assert(!std::is_invocable<RFn, T, int>::value, "" ); |
147 | } |
148 | { |
149 | // Bullet 3 |
150 | using T = Tag*; |
151 | using DT = DerFromTag*; |
152 | using CT = const Tag*; |
153 | using ST = std::unique_ptr<Tag>; |
154 | static_assert(std::is_invocable<Fn, T&, int>::value, "" ); |
155 | static_assert(std::is_invocable<Fn, DT&, int>::value, "" ); |
156 | static_assert(std::is_invocable<Fn, const T&, int>::value, "" ); |
157 | static_assert(std::is_invocable<Fn, T&&, int>::value, "" ); |
158 | static_assert(std::is_invocable<Fn, ST, int>::value, "" ); |
159 | static_assert(!std::is_invocable<Fn, CT&, int>::value, "" ); |
160 | static_assert(!std::is_invocable<RFn, T, int>::value, "" ); |
161 | } |
162 | } |
163 | { |
164 | // Bullets 4, 5 and 6 |
165 | using Fn = int(Tag::*); |
166 | static_assert(!std::is_invocable<Fn>::value, "" ); |
167 | { |
168 | // Bullet 4 |
169 | static_assert(std::is_invocable<Fn, Tag&>::value, "" ); |
170 | static_assert(std::is_invocable<Fn, DerFromTag&>::value, "" ); |
171 | static_assert(std::is_invocable<Fn, Tag&&>::value, "" ); |
172 | static_assert(std::is_invocable<Fn, Tag const&>::value, "" ); |
173 | } |
174 | { |
175 | // Bullet 5 |
176 | using T = std::reference_wrapper<Tag>; |
177 | using DT = std::reference_wrapper<DerFromTag>; |
178 | using CT = std::reference_wrapper<const Tag>; |
179 | static_assert(std::is_invocable<Fn, T&>::value, "" ); |
180 | static_assert(std::is_invocable<Fn, DT&>::value, "" ); |
181 | static_assert(std::is_invocable<Fn, const T&>::value, "" ); |
182 | static_assert(std::is_invocable<Fn, T&&>::value, "" ); |
183 | static_assert(std::is_invocable<Fn, CT&>::value, "" ); |
184 | } |
185 | { |
186 | // Bullet 6 |
187 | using T = Tag*; |
188 | using DT = DerFromTag*; |
189 | using CT = const Tag*; |
190 | using ST = std::unique_ptr<Tag>; |
191 | static_assert(std::is_invocable<Fn, T&>::value, "" ); |
192 | static_assert(std::is_invocable<Fn, DT&>::value, "" ); |
193 | static_assert(std::is_invocable<Fn, const T&>::value, "" ); |
194 | static_assert(std::is_invocable<Fn, T&&>::value, "" ); |
195 | static_assert(std::is_invocable<Fn, ST>::value, "" ); |
196 | static_assert(std::is_invocable<Fn, CT&>::value, "" ); |
197 | } |
198 | } |
199 | { // INVOKE bullet 7 |
200 | {// Function pointer |
201 | using Fp = void(*)(Tag&, int); |
202 | static_assert(std::is_invocable<Fp, Tag&, int>::value, "" ); |
203 | static_assert(std::is_invocable<Fp, DerFromTag&, int>::value, "" ); |
204 | static_assert(!std::is_invocable<Fp, const Tag&, int>::value, "" ); |
205 | static_assert(!std::is_invocable<Fp>::value, "" ); |
206 | static_assert(!std::is_invocable<Fp, Tag&>::value, "" ); |
207 | } |
208 | { |
209 | // Function reference |
210 | using Fp = void (&)(Tag&, int); |
211 | static_assert(std::is_invocable<Fp, Tag&, int>::value, "" ); |
212 | static_assert(std::is_invocable<Fp, DerFromTag&, int>::value, "" ); |
213 | static_assert(!std::is_invocable<Fp, const Tag&, int>::value, "" ); |
214 | static_assert(!std::is_invocable<Fp>::value, "" ); |
215 | static_assert(!std::is_invocable<Fp, Tag&>::value, "" ); |
216 | } |
217 | { |
218 | // Function object |
219 | using Fn = NotCallableWithInt; |
220 | static_assert(std::is_invocable<Fn, Tag>::value, "" ); |
221 | static_assert(!std::is_invocable<Fn, int>::value, "" ); |
222 | } |
223 | } |
224 | { |
225 | // Check that the conversion to the return type is properly checked |
226 | using Fn = int (*)(); |
227 | static_assert(std::is_invocable_r<Implicit, Fn>::value, "" ); |
228 | static_assert(std::is_invocable_r<double, Fn>::value, "" ); |
229 | static_assert(std::is_invocable_r<const volatile void, Fn>::value, "" ); |
230 | static_assert(!std::is_invocable_r<Explicit, Fn>::value, "" ); |
231 | } |
232 | { |
233 | // Check for is_invocable_v |
234 | using Fn = void (*)(); |
235 | static_assert(std::is_invocable_v<Fn>, "" ); |
236 | static_assert(!std::is_invocable_v<Fn, int>, "" ); |
237 | } |
238 | { |
239 | // Check for is_invocable_r_v |
240 | using Fn = void (*)(); |
241 | static_assert(std::is_invocable_r_v<void, Fn>, "" ); |
242 | static_assert(!std::is_invocable_r_v<int, Fn>, "" ); |
243 | } |
244 | return 0; |
245 | } |
246 | |