| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 376 | int main(int, char**) { |
| 377 | test(); |
| 378 | static_assert(test()); |
| 379 | |
| 380 | return 0; |
| 381 | } |
| 382 | |