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, c++17 |
10 | |
11 | // functional |
12 | |
13 | // template <class F, class... Args> |
14 | // constexpr unspecified bind_front(F&&, Args&&...); |
15 | |
16 | #include <functional> |
17 | #include <cassert> |
18 | #include <concepts> |
19 | #include <tuple> |
20 | #include <type_traits> |
21 | #include <utility> |
22 | |
23 | #include "callable_types.h" |
24 | #include "test_macros.h" |
25 | |
26 | struct CopyMoveInfo { |
27 | enum { none, copy, move } copy_kind; |
28 | |
29 | constexpr CopyMoveInfo() : copy_kind(none) {} |
30 | constexpr CopyMoveInfo(CopyMoveInfo const&) : copy_kind(copy) {} |
31 | constexpr CopyMoveInfo(CopyMoveInfo&&) : copy_kind(move) {} |
32 | }; |
33 | |
34 | template <class ...Args> |
35 | struct is_bind_frontable { |
36 | template <class ...LocalArgs> |
37 | static auto test(int) |
38 | -> decltype((void)std::bind_front(std::declval<LocalArgs>()...), std::true_type()); |
39 | |
40 | template <class...> |
41 | static std::false_type test(...); |
42 | |
43 | static constexpr bool value = decltype(test<Args...>(0))::value; |
44 | }; |
45 | |
46 | struct NotCopyMove { |
47 | NotCopyMove() = delete; |
48 | NotCopyMove(const NotCopyMove&) = delete; |
49 | NotCopyMove(NotCopyMove&&) = delete; |
50 | template <class ...Args> |
51 | void operator()(Args&& ...) const { } |
52 | }; |
53 | |
54 | struct NonConstCopyConstructible { |
55 | explicit NonConstCopyConstructible() {} |
56 | NonConstCopyConstructible(NonConstCopyConstructible&) {} |
57 | }; |
58 | |
59 | struct MoveConstructible { |
60 | explicit MoveConstructible() {} |
61 | MoveConstructible(MoveConstructible&&) {} |
62 | }; |
63 | |
64 | struct MakeTuple { |
65 | template <class ...Args> |
66 | constexpr auto operator()(Args&& ...args) const { |
67 | return std::make_tuple(std::forward<Args>(args)...); |
68 | } |
69 | }; |
70 | |
71 | template <int X> |
72 | struct Elem { |
73 | template <int Y> |
74 | constexpr bool operator==(Elem<Y> const&) const |
75 | { return X == Y; } |
76 | }; |
77 | |
78 | constexpr bool test() { |
79 | // Bind arguments, call without arguments |
80 | { |
81 | { |
82 | auto f = std::bind_front(MakeTuple{}); |
83 | assert(f() == std::make_tuple()); |
84 | } |
85 | { |
86 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}); |
87 | assert(f() == std::make_tuple(Elem<1>{})); |
88 | } |
89 | { |
90 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}); |
91 | assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{})); |
92 | } |
93 | { |
94 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{}); |
95 | assert(f() == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{})); |
96 | } |
97 | } |
98 | |
99 | // Bind no arguments, call with arguments |
100 | { |
101 | { |
102 | auto f = std::bind_front(MakeTuple{}); |
103 | assert(f(Elem<1>{}) == std::make_tuple(Elem<1>{})); |
104 | } |
105 | { |
106 | auto f = std::bind_front(MakeTuple{}); |
107 | assert(f(Elem<1>{}, Elem<2>{}) == std::make_tuple(Elem<1>{}, Elem<2>{})); |
108 | } |
109 | { |
110 | auto f = std::bind_front(MakeTuple{}); |
111 | assert(f(Elem<1>{}, Elem<2>{}, Elem<3>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{})); |
112 | } |
113 | } |
114 | |
115 | // Bind arguments, call with arguments |
116 | { |
117 | { |
118 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}); |
119 | assert(f(Elem<10>{}) == std::make_tuple(Elem<1>{}, Elem<10>{})); |
120 | } |
121 | { |
122 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}); |
123 | assert(f(Elem<10>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<10>{})); |
124 | } |
125 | { |
126 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{}); |
127 | assert(f(Elem<10>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}, Elem<10>{})); |
128 | } |
129 | |
130 | { |
131 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}); |
132 | assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<1>{}, Elem<10>{}, Elem<11>{})); |
133 | } |
134 | { |
135 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}); |
136 | assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<10>{}, Elem<11>{})); |
137 | } |
138 | { |
139 | auto f = std::bind_front(MakeTuple{}, Elem<1>{}, Elem<2>{}, Elem<3>{}); |
140 | assert(f(Elem<10>{}, Elem<11>{}) == std::make_tuple(Elem<1>{}, Elem<2>{}, Elem<3>{}, Elem<10>{}, Elem<11>{})); |
141 | } |
142 | } |
143 | |
144 | // Basic tests with fundamental types |
145 | { |
146 | int n = 2; |
147 | int m = 1; |
148 | int sum = 0; |
149 | auto add = [](int x, int y) { return x + y; }; |
150 | auto addN = [](int a, int b, int c, int d, int e, int f) { return a + b + c + d + e + f; }; |
151 | auto add_ref = [&](int x, int y) -> int& { return sum = x + y; }; |
152 | auto add_rref = [&](int x, int y) -> int&& { return std::move(sum = x + y); }; |
153 | |
154 | auto a = std::bind_front(add, m, n); |
155 | assert(a() == 3); |
156 | |
157 | auto b = std::bind_front(addN, m, n, m, m, m, m); |
158 | assert(b() == 7); |
159 | |
160 | auto c = std::bind_front(addN, n, m); |
161 | assert(c(1, 1, 1, 1) == 7); |
162 | |
163 | auto d = std::bind_front(add_ref, n, m); |
164 | std::same_as<int&> decltype(auto) dresult(d()); |
165 | assert(dresult == 3); |
166 | |
167 | auto e = std::bind_front(add_rref, n, m); |
168 | std::same_as<int&&> decltype(auto) eresult(e()); |
169 | assert(eresult == 3); |
170 | |
171 | auto f = std::bind_front(add, n); |
172 | assert(f(3) == 5); |
173 | |
174 | auto g = std::bind_front(add, n, 1); |
175 | assert(g() == 3); |
176 | |
177 | auto h = std::bind_front(addN, 1, 1, 1); |
178 | assert(h(2, 2, 2) == 9); |
179 | |
180 | auto i = std::bind_front(add_ref, n); |
181 | std::same_as<int&> decltype(auto) iresult(i(5)); |
182 | assert(iresult == 7); |
183 | |
184 | auto j = std::bind_front(add_rref, m); |
185 | std::same_as<int&&> decltype(auto) jresult(j(4)); |
186 | assert(jresult == 5); |
187 | } |
188 | |
189 | // Make sure we don't treat std::reference_wrapper specially. |
190 | { |
191 | auto add = [](std::reference_wrapper<int> a, std::reference_wrapper<int> b) { |
192 | return a.get() + b.get(); |
193 | }; |
194 | int i = 1, j = 2; |
195 | auto f = std::bind_front(add, std::ref(i)); |
196 | assert(f(std::ref(j)) == 3); |
197 | } |
198 | |
199 | // Make sure we can call a function that's a pointer to a member function. |
200 | { |
201 | struct MemberFunction { |
202 | constexpr bool foo(int, int) { return true; } |
203 | }; |
204 | MemberFunction value; |
205 | auto fn = std::bind_front(&MemberFunction::foo, value, 0); |
206 | assert(fn(0)); |
207 | } |
208 | |
209 | // Make sure that we copy the bound arguments into the unspecified-type. |
210 | { |
211 | auto add = [](int x, int y) { return x + y; }; |
212 | int n = 2; |
213 | auto i = std::bind_front(add, n, 1); |
214 | n = 100; |
215 | assert(i() == 3); |
216 | } |
217 | |
218 | // Make sure we pass the bound arguments to the function object |
219 | // with the right value category. |
220 | { |
221 | { |
222 | auto wasCopied = [](CopyMoveInfo info) { |
223 | return info.copy_kind == CopyMoveInfo::copy; |
224 | }; |
225 | CopyMoveInfo info; |
226 | auto copied = std::bind_front(wasCopied, info); |
227 | assert(copied()); |
228 | } |
229 | |
230 | { |
231 | auto wasMoved = [](CopyMoveInfo info) { |
232 | return info.copy_kind == CopyMoveInfo::move; |
233 | }; |
234 | CopyMoveInfo info; |
235 | auto moved = std::bind_front(wasMoved, info); |
236 | assert(std::move(moved)()); |
237 | } |
238 | } |
239 | |
240 | // Make sure we call the correctly cv-ref qualified operator() based on the |
241 | // value category of the bind_front unspecified-type. |
242 | { |
243 | struct F { |
244 | constexpr int operator()() & { return 1; } |
245 | constexpr int operator()() const& { return 2; } |
246 | constexpr int operator()() && { return 3; } |
247 | constexpr int operator()() const&& { return 4; } |
248 | }; |
249 | auto x = std::bind_front(F{}); |
250 | using X = decltype(x); |
251 | assert(static_cast<X&>(x)() == 1); |
252 | assert(static_cast<X const&>(x)() == 2); |
253 | assert(static_cast<X&&>(x)() == 3); |
254 | assert(static_cast<X const&&>(x)() == 4); |
255 | } |
256 | |
257 | // Make sure the bind_front unspecified-type is NOT invocable when the call would select a |
258 | // differently-qualified operator(). |
259 | // |
260 | // For example, if the call to `operator()() &` is ill-formed, the call to the unspecified-type |
261 | // should be ill-formed and not fall back to the `operator()() const&` overload. |
262 | { |
263 | // Make sure we delete the & overload when the underlying call isn't valid |
264 | { |
265 | struct F { |
266 | void operator()() & = delete; |
267 | void operator()() const&; |
268 | void operator()() &&; |
269 | void operator()() const&&; |
270 | }; |
271 | using X = decltype(std::bind_front(F{})); |
272 | static_assert(!std::is_invocable_v<X&>); |
273 | static_assert( std::is_invocable_v<X const&>); |
274 | static_assert( std::is_invocable_v<X>); |
275 | static_assert( std::is_invocable_v<X const>); |
276 | } |
277 | |
278 | // There's no way to make sure we delete the const& overload when the underlying call isn't valid, |
279 | // so we can't check this one. |
280 | |
281 | // Make sure we delete the && overload when the underlying call isn't valid |
282 | { |
283 | struct F { |
284 | void operator()() &; |
285 | void operator()() const&; |
286 | void operator()() && = delete; |
287 | void operator()() const&&; |
288 | }; |
289 | using X = decltype(std::bind_front(F{})); |
290 | static_assert( std::is_invocable_v<X&>); |
291 | static_assert( std::is_invocable_v<X const&>); |
292 | static_assert(!std::is_invocable_v<X>); |
293 | static_assert( std::is_invocable_v<X const>); |
294 | } |
295 | |
296 | // Make sure we delete the const&& overload when the underlying call isn't valid |
297 | { |
298 | struct F { |
299 | void operator()() &; |
300 | void operator()() const&; |
301 | void operator()() &&; |
302 | void operator()() const&& = delete; |
303 | }; |
304 | using X = decltype(std::bind_front(F{})); |
305 | static_assert( std::is_invocable_v<X&>); |
306 | static_assert( std::is_invocable_v<X const&>); |
307 | static_assert( std::is_invocable_v<X>); |
308 | static_assert(!std::is_invocable_v<X const>); |
309 | } |
310 | } |
311 | |
312 | // Some examples by Tim Song |
313 | { |
314 | { |
315 | struct T { }; |
316 | struct F { |
317 | void operator()(T&&) const &; |
318 | void operator()(T&&) && = delete; |
319 | }; |
320 | using X = decltype(std::bind_front(F{})); |
321 | static_assert(!std::is_invocable_v<X, T>); |
322 | } |
323 | |
324 | { |
325 | struct T { }; |
326 | struct F { |
327 | void operator()(T const&) const; |
328 | void operator()(T&&) const = delete; |
329 | }; |
330 | using X = decltype(std::bind_front(F{}, T{})); |
331 | static_assert(!std::is_invocable_v<X>); |
332 | } |
333 | } |
334 | |
335 | // Test properties of the constructor of the unspecified-type returned by bind_front. |
336 | { |
337 | { |
338 | MoveOnlyCallable<bool> value(true); |
339 | auto ret = std::bind_front(std::move(value), 1); |
340 | assert(ret()); |
341 | assert(ret(1, 2, 3)); |
342 | |
343 | auto ret1 = std::move(ret); |
344 | assert(!ret()); |
345 | assert(ret1()); |
346 | assert(ret1(1, 2, 3)); |
347 | |
348 | using RetT = decltype(ret); |
349 | static_assert( std::is_move_constructible<RetT>::value); |
350 | static_assert(!std::is_copy_constructible<RetT>::value); |
351 | static_assert(!std::is_move_assignable<RetT>::value); |
352 | static_assert(!std::is_copy_assignable<RetT>::value); |
353 | } |
354 | { |
355 | CopyCallable<bool> value(true); |
356 | auto ret = std::bind_front(value, 1); |
357 | assert(ret()); |
358 | assert(ret(1, 2, 3)); |
359 | |
360 | auto ret1 = std::move(ret); |
361 | assert(ret1()); |
362 | assert(ret1(1, 2, 3)); |
363 | |
364 | auto ret2 = std::bind_front(std::move(value), 1); |
365 | assert(!ret()); |
366 | assert(ret2()); |
367 | assert(ret2(1, 2, 3)); |
368 | |
369 | using RetT = decltype(ret); |
370 | static_assert( std::is_move_constructible<RetT>::value); |
371 | static_assert( std::is_copy_constructible<RetT>::value); |
372 | static_assert(!std::is_move_assignable<RetT>::value); |
373 | static_assert(!std::is_copy_assignable<RetT>::value); |
374 | } |
375 | { |
376 | CopyAssignableWrapper value(true); |
377 | using RetT = decltype(std::bind_front(value, 1)); |
378 | |
379 | static_assert(std::is_move_constructible<RetT>::value); |
380 | static_assert(std::is_copy_constructible<RetT>::value); |
381 | static_assert(std::is_move_assignable<RetT>::value); |
382 | static_assert(std::is_copy_assignable<RetT>::value); |
383 | } |
384 | { |
385 | MoveAssignableWrapper value(true); |
386 | using RetT = decltype(std::bind_front(std::move(value), 1)); |
387 | |
388 | static_assert( std::is_move_constructible<RetT>::value); |
389 | static_assert(!std::is_copy_constructible<RetT>::value); |
390 | static_assert( std::is_move_assignable<RetT>::value); |
391 | static_assert(!std::is_copy_assignable<RetT>::value); |
392 | } |
393 | } |
394 | |
395 | // Make sure bind_front is SFINAE friendly |
396 | { |
397 | static_assert(!std::is_constructible_v<NotCopyMove, NotCopyMove&>); |
398 | static_assert(!std::is_move_constructible_v<NotCopyMove>); |
399 | static_assert(!is_bind_frontable<NotCopyMove>::value); |
400 | static_assert(!is_bind_frontable<NotCopyMove&>::value); |
401 | |
402 | auto takeAnything = [](auto&& ...) { }; |
403 | static_assert(!std::is_constructible_v<MoveConstructible, MoveConstructible&>); |
404 | static_assert( std::is_move_constructible_v<MoveConstructible>); |
405 | static_assert( is_bind_frontable<decltype(takeAnything), MoveConstructible>::value); |
406 | static_assert(!is_bind_frontable<decltype(takeAnything), MoveConstructible&>::value); |
407 | |
408 | static_assert( std::is_constructible_v<NonConstCopyConstructible, NonConstCopyConstructible&>); |
409 | static_assert(!std::is_move_constructible_v<NonConstCopyConstructible>); |
410 | static_assert(!is_bind_frontable<decltype(takeAnything), NonConstCopyConstructible&>::value); |
411 | static_assert(!is_bind_frontable<decltype(takeAnything), NonConstCopyConstructible>::value); |
412 | } |
413 | |
414 | // Make sure bind_front's unspecified type's operator() is SFINAE-friendly |
415 | { |
416 | using T = decltype(std::bind_front(std::declval<int(*)(int, int)>(), 1)); |
417 | static_assert(!std::is_invocable<T>::value); |
418 | static_assert( std::is_invocable<T, int>::value); |
419 | static_assert(!std::is_invocable<T, void*>::value); |
420 | static_assert(!std::is_invocable<T, int, int>::value); |
421 | } |
422 | |
423 | return true; |
424 | } |
425 | |
426 | int main(int, char**) { |
427 | test(); |
428 | static_assert(test()); |
429 | |
430 | return 0; |
431 | } |
432 | |