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