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