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