xref: /llvm-project/libcxx/test/std/utilities/function.objects/func.bind_front/bind_front.pass.cpp (revision 84a50f5911bf8300cc4bea1f60673ede2145345b)
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++98, c++03, c++11, c++14, c++17
10 
11 // functional
12 
13 // template <class F, class... Args> constexpr unspecified bind_front(F&&, Args&&...);
14 
15 #include <functional>
16 
17 #include "callable_types.h"
18 #include "test_macros.h"
19 
20 constexpr int add(int a, int b) { return a + b; }
21 
22 constexpr int long_test(int a, int b, int c, int d, int e, int f) {
23   return a + b + c + d + e + f;
24 }
25 
26 struct Foo {
27   int a;
28   int b;
29 };
30 
31 struct FooCall {
32   constexpr Foo operator()(int a, int b) { return Foo{a, b}; }
33 };
34 
35 struct S {
36   constexpr bool operator()(int a) { return a == 1; }
37 };
38 
39 struct CopyMoveInfo {
40   enum { none, copy, move } copy_kind;
41 
42   constexpr CopyMoveInfo() : copy_kind(none) {}
43   constexpr CopyMoveInfo(CopyMoveInfo const&) : copy_kind(copy) {}
44   constexpr CopyMoveInfo(CopyMoveInfo&&) : copy_kind(move) {}
45 };
46 
47 constexpr bool wasCopied(CopyMoveInfo info) {
48   return info.copy_kind == CopyMoveInfo::copy;
49 }
50 constexpr bool wasMoved(CopyMoveInfo info) {
51   return info.copy_kind == CopyMoveInfo::move;
52 }
53 
54 constexpr void basic_tests() {
55   int n = 2;
56   int m = 1;
57 
58   auto a = std::bind_front(add, m, n);
59   assert(a() == 3);
60 
61   auto b = std::bind_front(long_test, m, n, m, m, m, m);
62   assert(b() == 7);
63 
64   auto c = std::bind_front(long_test, n, m);
65   assert(c(1, 1, 1, 1) == 7);
66 
67   auto d = std::bind_front(S{}, m);
68   assert(d());
69 
70   auto f = std::bind_front(add, n);
71   assert(f(3) == 5);
72 
73   auto g = std::bind_front(add, n, 1);
74   assert(g() == 3);
75 
76   auto h = std::bind_front(long_test, 1, 1, 1);
77   assert(h(2, 2, 2) == 9);
78 
79   // Make sure the arg is passed by value.
80   auto i = std::bind_front(add, n, 1);
81   n = 100;
82   assert(i() == 3);
83 
84   CopyMoveInfo info;
85   auto copied = std::bind_front(wasCopied, info);
86   assert(copied());
87 
88   auto moved = std::bind_front(wasMoved, info);
89   assert(std::move(moved)());
90 }
91 
92 struct variadic_fn {
93   template <class... Args>
94   constexpr int operator()(Args&&... args) {
95     return sizeof...(args);
96   }
97 };
98 
99 constexpr void test_variadic() {
100   variadic_fn value;
101   auto fn = std::bind_front(value, 0, 0, 0);
102   assert(fn(0, 0, 0) == 6);
103 }
104 
105 struct mutable_callable {
106   bool should_call_const;
107 
108   constexpr bool operator()(int, int) {
109     assert(!should_call_const);
110     return true;
111   }
112   constexpr bool operator()(int, int) const {
113     assert(should_call_const);
114     return true;
115   }
116 };
117 
118 constexpr void test_mutable() {
119   const mutable_callable v1{true};
120   const auto fn1 = std::bind_front(v1, 0);
121   assert(fn1(0));
122 
123   mutable_callable v2{false};
124   auto fn2 = std::bind_front(v2, 0);
125   assert(fn2(0));
126 };
127 
128 struct call_member {
129   constexpr bool member(int, int) { return true; }
130 };
131 
132 constexpr void test_call_member() {
133   call_member value;
134   auto fn = std::bind_front(&call_member::member, value, 0);
135   assert(fn(0));
136 }
137 
138 struct no_const_lvalue {
139   constexpr void operator()(int) && {};
140 };
141 
142 constexpr auto make_no_const_lvalue(int x) {
143   // This is to test that bind_front works when something like the following would not:
144   // return [nc = no_const_lvalue{}, x] { return nc(x); };
145   // Above would not work because it would look for a () const & overload.
146   return std::bind_front(no_const_lvalue{}, x);
147 }
148 
149 constexpr void test_no_const_lvalue() { make_no_const_lvalue(1)(); }
150 
151 constexpr void constructor_tests() {
152   {
153     MoveOnlyCallable value(true);
154     using RetT = decltype(std::bind_front(std::move(value), 1));
155 
156     static_assert(std::is_move_constructible<RetT>::value);
157     static_assert(!std::is_copy_constructible<RetT>::value);
158     static_assert(!std::is_move_assignable<RetT>::value);
159     static_assert(!std::is_copy_assignable<RetT>::value);
160 
161     auto ret = std::bind_front(std::move(value), 1);
162     assert(ret());
163     assert(ret(1, 2, 3));
164 
165     auto ret1 = std::move(ret);
166     assert(!ret());
167     assert(ret1());
168     assert(ret1(1, 2, 3));
169   }
170   {
171     CopyCallable value(true);
172     using RetT = decltype(std::bind_front(value, 1));
173 
174     static_assert(std::is_move_constructible<RetT>::value);
175     static_assert(std::is_copy_constructible<RetT>::value);
176     static_assert(!std::is_move_assignable<RetT>::value);
177     static_assert(!std::is_copy_assignable<RetT>::value);
178 
179     auto ret = std::bind_front(value, 1);
180     assert(ret());
181     assert(ret(1, 2, 3));
182 
183     auto ret1 = std::move(ret);
184     assert(ret1());
185     assert(ret1(1, 2, 3));
186 
187     auto ret2 = std::bind_front(std::move(value), 1);
188     assert(!ret());
189     assert(ret2());
190     assert(ret2(1, 2, 3));
191   }
192   {
193     CopyAssignableWrapper value(true);
194     using RetT = decltype(std::bind_front(value, 1));
195 
196     static_assert(std::is_move_constructible<RetT>::value);
197     static_assert(std::is_copy_constructible<RetT>::value);
198     static_assert(std::is_move_assignable<RetT>::value);
199     static_assert(std::is_copy_assignable<RetT>::value);
200   }
201   {
202     MoveAssignableWrapper value(true);
203     using RetT = decltype(std::bind_front(std::move(value), 1));
204 
205     static_assert(std::is_move_constructible<RetT>::value);
206     static_assert(!std::is_copy_constructible<RetT>::value);
207     static_assert(std::is_move_assignable<RetT>::value);
208     static_assert(!std::is_copy_assignable<RetT>::value);
209   }
210 }
211 
212 template <class Res, class F, class... Args>
213 constexpr void test_return(F&& value, Args&&... args) {
214   auto ret =
215       std::bind_front(std::forward<F>(value), std::forward<Args>(args)...);
216   static_assert(std::is_same<decltype(ret()), Res>::value);
217 }
218 
219 constexpr void test_return_types() {
220   test_return<Foo>(FooCall{}, 1, 2);
221   test_return<bool>(S{}, 1);
222   test_return<int>(add, 2, 2);
223 }
224 
225 constexpr void test_arg_count() {
226   using T = decltype(std::bind_front(add, 1));
227   static_assert(!std::is_invocable<T>::value);
228   static_assert(std::is_invocable<T, int>::value);
229 }
230 
231 template <class... Args>
232 struct is_bind_frontable {
233   template <class... LocalArgs>
234   static auto test(int)
235       -> decltype((void)std::bind_front(std::declval<LocalArgs>()...),
236                   std::true_type());
237 
238   template <class...>
239   static std::false_type test(...);
240 
241   static constexpr bool value = decltype(test<Args...>(0))::value;
242 };
243 
244 struct NotCopyMove {
245   NotCopyMove() = delete;
246   NotCopyMove(const NotCopyMove&) = delete;
247   NotCopyMove(NotCopyMove&&) = delete;
248   void operator()() {}
249 };
250 
251 struct NonConstCopyConstructible {
252   explicit NonConstCopyConstructible() {}
253   NonConstCopyConstructible(NonConstCopyConstructible&) {}
254 };
255 
256 struct MoveConstructible {
257   explicit MoveConstructible() {}
258   MoveConstructible(MoveConstructible&&) {}
259 };
260 
261 constexpr void test_invocability() {
262   static_assert(!std::is_constructible_v<NotCopyMove, NotCopyMove>);
263   static_assert(!std::is_move_constructible_v<NotCopyMove>);
264   static_assert(!is_bind_frontable<NotCopyMove>::value);
265   static_assert(!is_bind_frontable<NotCopyMove&>::value);
266 
267   static_assert(
268       !std::is_constructible_v<MoveConstructible, MoveConstructible&>);
269   static_assert(std::is_move_constructible_v<MoveConstructible>);
270   static_assert(is_bind_frontable<variadic_fn, MoveConstructible>::value);
271   static_assert(
272       !is_bind_frontable<variadic_fn, MoveConstructible&>::value);
273 
274   static_assert(std::is_constructible_v<NonConstCopyConstructible,
275                                         NonConstCopyConstructible&>);
276   static_assert(!std::is_move_constructible_v<NonConstCopyConstructible>);
277   static_assert(
278       !is_bind_frontable<variadic_fn, NonConstCopyConstructible&>::value);
279   static_assert(
280       !is_bind_frontable<variadic_fn, NonConstCopyConstructible>::value);
281 }
282 
283 constexpr bool test() {
284   basic_tests();
285   constructor_tests();
286   test_return_types();
287   test_arg_count();
288   test_variadic();
289   test_mutable();
290   test_call_member();
291   test_no_const_lvalue();
292   test_invocability();
293 
294   return true;
295 }
296 
297 int main(int, char**) {
298   test();
299   static_assert(test());
300 
301   return 0;
302 }
303