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 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 11 12 // <algorithm> 13 14 // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O, 15 // copy_constructible F, class Proj = identity> 16 // requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>> 17 // constexpr ranges::unary_transform_result<I, O> 18 // ranges::transform(I first1, S last1, O result, F op, Proj proj = {}); 19 // template<input_range R, weakly_incrementable O, copy_constructible F, 20 // class Proj = identity> 21 // requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>> 22 // constexpr ranges::unary_transform_result<borrowed_iterator_t<R>, O> 23 // ranges::transform(R&& r, O result, F op, Proj proj = {}); 24 // template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2, 25 // weakly_incrementable O, copy_constructible F, class Proj1 = identity, 26 // class Proj2 = identity> 27 // requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>, 28 // projected<I2, Proj2>>> 29 // constexpr ranges::binary_transform_result<I1, I2, O> 30 // ranges::transform(I1 first1, S1 last1, I2 first2, S2 last2, O result, 31 // F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); 32 // template<input_range R1, input_range R2, weakly_incrementable O, 33 // copy_constructible F, class Proj1 = identity, class Proj2 = identity> 34 // requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R1>, Proj1>, 35 // projected<iterator_t<R2>, Proj2>>> 36 // constexpr ranges::binary_transform_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O> 37 // ranges::transform(R1&& r1, R2&& r2, O result, 38 // F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {}); 39 40 #include <algorithm> 41 #include <array> 42 #include <cassert> 43 #include <ranges> 44 45 #include "test_iterators.h" 46 #include "almost_satisfies_types.h" 47 48 struct BinaryFunc { 49 int operator()(int, int); 50 }; 51 52 template <class Range> 53 concept HasTranformR = requires(Range r, int* out) { 54 std::ranges::transform(r, out, std::identity{}); 55 std::ranges::transform(r, r, out, BinaryFunc{}); 56 }; 57 static_assert(HasTranformR<std::array<int, 1>>); 58 static_assert(!HasTranformR<int>); 59 static_assert(!HasTranformR<InputRangeNotDerivedFrom>); 60 static_assert(!HasTranformR<InputRangeNotIndirectlyReadable>); 61 static_assert(!HasTranformR<InputRangeNotInputOrOutputIterator>); 62 static_assert(!HasTranformR<InputRangeNotSentinelSemiregular>); 63 static_assert(!HasTranformR<InputRangeNotSentinelEqualityComparableWith>); 64 65 template <class It, class Sent = It> 66 concept HasTransformIt = requires(It it, Sent sent, int* out) { 67 std::ranges::transform(it, sent, out, std::identity{}); 68 std::ranges::transform(it, sent, it, sent, out, BinaryFunc{}); 69 }; 70 static_assert(HasTransformIt<int*>); 71 static_assert(!HasTransformIt<InputIteratorNotDerivedFrom>); 72 static_assert(!HasTransformIt<InputIteratorNotIndirectlyReadable>); 73 static_assert(!HasTransformIt<InputIteratorNotInputOrOutputIterator>); 74 static_assert(!HasTransformIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>); 75 static_assert(!HasTransformIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>); 76 77 template <class It> 78 concept HasTransformOut = requires(int* it, int* sent, It out, std::array<int, 2> range) { 79 std::ranges::transform(it, sent, out, std::identity{}); 80 std::ranges::transform(it, sent, it, sent, out, BinaryFunc{}); 81 std::ranges::transform(range, out, std::identity{}); 82 std::ranges::transform(range, range, out, BinaryFunc{}); 83 }; 84 static_assert(HasTransformOut<int*>); 85 static_assert(!HasTransformOut<WeaklyIncrementableNotMovable>); 86 87 // check indirectly_readable 88 static_assert(HasTransformOut<char*>); 89 static_assert(!HasTransformOut<int**>); 90 91 struct MoveOnlyFunctor { 92 MoveOnlyFunctor(const MoveOnlyFunctor&) = delete; 93 MoveOnlyFunctor(MoveOnlyFunctor&&) = default; 94 int operator()(int); 95 int operator()(int, int); 96 }; 97 98 template <class Func> 99 concept HasTransformFuncUnary = requires(int* it, int* sent, int* out, std::array<int, 2> range, Func func) { 100 std::ranges::transform(it, sent, out, func); 101 std::ranges::transform(range, out, func); 102 }; 103 static_assert(HasTransformFuncUnary<std::identity>); 104 static_assert(!HasTransformFuncUnary<MoveOnlyFunctor>); 105 106 template <class Func> 107 concept HasTransformFuncBinary = requires(int* it, int* sent, int* out, std::array<int, 2> range, Func func) { 108 std::ranges::transform(it, sent, it, sent, out, func); 109 std::ranges::transform(range, range, out, func); 110 }; 111 static_assert(HasTransformFuncBinary<BinaryFunc>); 112 static_assert(!HasTransformFuncBinary<MoveOnlyFunctor>); 113 114 static_assert(std::is_same_v<std::ranges::unary_transform_result<int, long>, std::ranges::in_out_result<int, long>>); 115 static_assert(std::is_same_v<std::ranges::binary_transform_result<int, long, char>, 116 std::ranges::in_in_out_result<int, long, char>>); 117 118 template <class In1, class In2, class Out, class Sent1, class Sent2> 119 constexpr bool test_iterators() { 120 { // simple 121 { // unary 122 { 123 int a[] = {1, 2, 3, 4, 5}; 124 int b[5]; 125 std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret = 126 std::ranges::transform(In1(a), Sent1(In1(a + 5)), Out(b), [](int i) { return i * 2; }); 127 assert((std::to_array(b) == std::array{2, 4, 6, 8, 10})); 128 assert(base(ret.in) == a + 5); 129 assert(base(ret.out) == b + 5); 130 } 131 132 { 133 int a[] = {1, 2, 3, 4, 5}; 134 int b[5]; 135 auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 5))); 136 std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret = 137 std::ranges::transform(range, Out(b), [](int i) { return i * 2; }); 138 assert((std::to_array(b) == std::array{2, 4, 6, 8, 10})); 139 assert(base(ret.in) == a + 5); 140 assert(base(ret.out) == b + 5); 141 } 142 } 143 144 { // binary 145 { 146 int a[] = {1, 2, 3, 4, 5}; 147 int b[] = {5, 4, 3, 2, 1}; 148 int c[5]; 149 150 std::same_as<std::ranges::in_in_out_result<In1, In2, Out>> decltype(auto) ret = std::ranges::transform( 151 In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; }); 152 153 assert((std::to_array(c) == std::array{6, 6, 6, 6, 6})); 154 assert(base(ret.in1) == a + 5); 155 assert(base(ret.in2) == b + 5); 156 assert(base(ret.out) == c + 5); 157 } 158 159 { 160 int a[] = {1, 2, 3, 4, 5}; 161 int b[] = {5, 4, 3, 2, 1}; 162 int c[5]; 163 164 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5))); 165 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5))); 166 167 std::same_as<std::ranges::in_in_out_result<In1, In2, Out>> decltype(auto) ret = std::ranges::transform( 168 range1, range2, Out(c), [](int i, int j) { return i + j; }); 169 170 assert((std::to_array(c) == std::array{6, 6, 6, 6, 6})); 171 assert(base(ret.in1) == a + 5); 172 assert(base(ret.in2) == b + 5); 173 assert(base(ret.out) == c + 5); 174 } 175 } 176 } 177 178 { // first range empty 179 { // unary 180 { 181 int a[] = {}; 182 int b[5]; 183 auto ret = std::ranges::transform(In1(a), Sent1(In1(a)), Out(b), [](int i) { return i * 2; }); 184 assert(base(ret.in) == a); 185 assert(base(ret.out) == b); 186 } 187 188 { 189 int a[] = {}; 190 int b[5]; 191 auto range = std::ranges::subrange(In1(a), Sent1(In1(a))); 192 auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; }); 193 assert(base(ret.in) == a); 194 assert(base(ret.out) == b); 195 } 196 } 197 198 { // binary 199 { 200 int a[] = {}; 201 int b[] = {5, 4, 3, 2, 1}; 202 int c[5]; 203 204 auto ret = std::ranges::transform( 205 In1(a), Sent1(In1(a)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; }); 206 207 assert(base(ret.in1) == a); 208 assert(base(ret.in2) == b); 209 assert(base(ret.out) == c); 210 } 211 212 { 213 int a[] = {}; 214 int b[] = {5, 4, 3, 2, 1}; 215 int c[5]; 216 217 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a))); 218 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5))); 219 220 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; }); 221 222 assert(base(ret.in1) == a); 223 assert(base(ret.in2) == b); 224 assert(base(ret.out) == c); 225 } 226 } 227 } 228 229 { // second range empty (binary) 230 { 231 int a[] = {5, 4, 3, 2, 1}; 232 int b[] = {}; 233 int c[5]; 234 235 auto ret = std::ranges::transform( 236 In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b)), Out(c), [](int i, int j) { return i + j; }); 237 238 assert(base(ret.in1) == a); 239 assert(base(ret.in2) == b); 240 assert(base(ret.out) == c); 241 } 242 243 { 244 int a[] = {5, 4, 3, 2, 1}; 245 int b[] = {}; 246 int c[5]; 247 248 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5))); 249 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b))); 250 251 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; }); 252 253 assert(base(ret.in1) == a); 254 assert(base(ret.in2) == b); 255 assert(base(ret.out) == c); 256 } 257 } 258 259 { // both ranges empty (binary) 260 { 261 int a[] = {}; 262 int b[] = {}; 263 int c[5]; 264 265 auto ret = std::ranges::transform( 266 In1(a), Sent1(In1(a)), In2(b), Sent2(In2(b)), Out(c), [](int i, int j) { return i + j; }); 267 268 assert(base(ret.in1) == a); 269 assert(base(ret.in2) == b); 270 assert(base(ret.out) == c); 271 } 272 273 { 274 int a[] = {}; 275 int b[] = {}; 276 int c[5]; 277 278 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a))); 279 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b))); 280 281 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; }); 282 283 assert(base(ret.in1) == a); 284 assert(base(ret.in2) == b); 285 assert(base(ret.out) == c); 286 } 287 } 288 289 { // first range one element 290 { // unary 291 { 292 int a[] = {2}; 293 int b[5]; 294 auto ret = std::ranges::transform(In1(a), Sent1(In1(a + 1)), Out(b), [](int i) { return i * 2; }); 295 assert(b[0] == 4); 296 assert(base(ret.in) == a + 1); 297 assert(base(ret.out) == b + 1); 298 } 299 300 { 301 int a[] = {2}; 302 int b[5]; 303 auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 1))); 304 auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; }); 305 assert(b[0] == 4); 306 assert(base(ret.in) == a + 1); 307 assert(base(ret.out) == b + 1); 308 } 309 } 310 311 { // binary 312 { 313 int a[] = {2}; 314 int b[] = {5, 4, 3, 2, 1}; 315 int c[5]; 316 317 auto ret = std::ranges::transform( 318 In1(a), Sent1(In1(a + 1)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; }); 319 320 assert(c[0] == 7); 321 assert(base(ret.in1) == a + 1); 322 assert(base(ret.in2) == b + 1); 323 assert(base(ret.out) == c + 1); 324 } 325 326 { 327 int a[] = {2}; 328 int b[] = {5, 4, 3, 2, 1}; 329 int c[5]; 330 331 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 1))); 332 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5))); 333 334 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; }); 335 336 assert(c[0] == 7); 337 assert(base(ret.in1) == a + 1); 338 assert(base(ret.in2) == b + 1); 339 assert(base(ret.out) == c + 1); 340 } 341 } 342 } 343 344 { // second range contains one element (binary) 345 { 346 int a[] = {5, 4, 3, 2, 1}; 347 int b[] = {4}; 348 int c[5]; 349 350 auto ret = std::ranges::transform( 351 In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b + 1)), Out(c), [](int i, int j) { return i + j; }); 352 353 assert(c[0] == 9); 354 assert(base(ret.in1) == a + 1); 355 assert(base(ret.in2) == b + 1); 356 assert(base(ret.out) == c + 1); 357 } 358 359 { 360 int a[] = {5, 4, 3, 2, 1}; 361 int b[] = {4}; 362 int c[5]; 363 364 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5))); 365 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 1))); 366 367 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; }); 368 369 assert(c[0] == 9); 370 assert(base(ret.in1) == a + 1); 371 assert(base(ret.in2) == b + 1); 372 assert(base(ret.out) == c + 1); 373 } 374 } 375 376 { // check that the transform function and projection call counts are correct 377 { // unary 378 { 379 int predCount = 0; 380 int projCount = 0; 381 auto pred = [&](int) { ++predCount; return 1; }; 382 auto proj = [&](int) { ++projCount; return 0; }; 383 int a[] = {1, 2, 3, 4}; 384 std::array<int, 4> c; 385 std::ranges::transform(In1(a), Sent1(In1(a + 4)), Out(c.data()), pred, proj); 386 assert(predCount == 4); 387 assert(projCount == 4); 388 assert((c == std::array{1, 1, 1, 1})); 389 } 390 { 391 int predCount = 0; 392 int projCount = 0; 393 auto pred = [&](int) { ++predCount; return 1; }; 394 auto proj = [&](int) { ++projCount; return 0; }; 395 int a[] = {1, 2, 3, 4}; 396 std::array<int, 4> c; 397 auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 4))); 398 std::ranges::transform(range, Out(c.data()), pred, proj); 399 assert(predCount == 4); 400 assert(projCount == 4); 401 assert((c == std::array{1, 1, 1, 1})); 402 } 403 } 404 { // binary 405 { 406 int predCount = 0; 407 int proj1Count = 0; 408 int proj2Count = 0; 409 auto pred = [&](int, int) { ++predCount; return 1; }; 410 auto proj1 = [&](int) { ++proj1Count; return 0; }; 411 auto proj2 = [&](int) { ++proj2Count; return 0; }; 412 int a[] = {1, 2, 3, 4}; 413 int b[] = {1, 2, 3, 4}; 414 std::array<int, 4> c; 415 std::ranges::transform(In1(a), Sent1(In1(a + 4)), In2(b), Sent2(In2(b + 4)), Out(c.data()), pred, proj1, proj2); 416 assert(predCount == 4); 417 assert(proj1Count == 4); 418 assert(proj2Count == 4); 419 assert((c == std::array{1, 1, 1, 1})); 420 } 421 { 422 int predCount = 0; 423 int proj1Count = 0; 424 int proj2Count = 0; 425 auto pred = [&](int, int) { ++predCount; return 1; }; 426 auto proj1 = [&](int) { ++proj1Count; return 0; }; 427 auto proj2 = [&](int) { ++proj2Count; return 0; }; 428 int a[] = {1, 2, 3, 4}; 429 int b[] = {1, 2, 3, 4}; 430 std::array<int, 4> c; 431 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 4))); 432 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 4))); 433 std::ranges::transform(range1, range2, Out(c.data()), pred, proj1, proj2); 434 assert(predCount == 4); 435 assert(proj1Count == 4); 436 assert(proj2Count == 4); 437 assert((c == std::array{1, 1, 1, 1})); 438 } 439 } 440 } 441 442 return true; 443 } 444 445 template <class In2, class Out, class Sent2 = In2> 446 constexpr void test_iterator_in1() { 447 test_iterators<cpp17_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp17_input_iterator<int*>>, Sent2>(); 448 test_iterators<cpp20_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp20_input_iterator<int*>>, Sent2>(); 449 test_iterators<forward_iterator<int*>, In2, Out, forward_iterator<int*>, Sent2>(); 450 test_iterators<bidirectional_iterator<int*>, In2, Out, bidirectional_iterator<int*>, Sent2>(); 451 test_iterators<random_access_iterator<int*>, In2, Out, random_access_iterator<int*>, Sent2>(); 452 test_iterators<contiguous_iterator<int*>, In2, Out, contiguous_iterator<int*>, Sent2>(); 453 test_iterators<int*, In2, Out, int*, Sent2>(); 454 // static_asserting here to avoid hitting the constant evaluation step limit 455 static_assert(test_iterators<cpp17_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp17_input_iterator<int*>>, Sent2>()); 456 static_assert(test_iterators<cpp20_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp20_input_iterator<int*>>, Sent2>()); 457 static_assert(test_iterators<forward_iterator<int*>, In2, Out, forward_iterator<int*>, Sent2>()); 458 static_assert(test_iterators<bidirectional_iterator<int*>, In2, Out, bidirectional_iterator<int*>, Sent2>()); 459 static_assert(test_iterators<random_access_iterator<int*>, In2, Out, random_access_iterator<int*>, Sent2>()); 460 static_assert(test_iterators<contiguous_iterator<int*>, In2, Out, contiguous_iterator<int*>, Sent2>()); 461 static_assert(test_iterators<int*, In2, Out, int*, Sent2>()); 462 } 463 464 template <class Out> 465 void test_iterators_in1_in2() { 466 test_iterator_in1<cpp17_input_iterator<int*>, Out, sentinel_wrapper<cpp17_input_iterator<int*>>>(); 467 test_iterator_in1<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>(); 468 test_iterator_in1<forward_iterator<int*>, Out>(); 469 test_iterator_in1<bidirectional_iterator<int*>, Out>(); 470 test_iterator_in1<random_access_iterator<int*>, Out>(); 471 test_iterator_in1<contiguous_iterator<int*>, Out>(); 472 test_iterator_in1<int*, Out>(); 473 } 474 475 constexpr bool test() { 476 { // check that std::ranges::dangling is returned properly 477 { // unary 478 std::array<int, 5> b; 479 std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret = 480 std::ranges::transform(std::array{1, 2, 3, 5, 4}, b.data(), [](int i) { return i * i; }); 481 assert((b == std::array{1, 4, 9, 25, 16})); 482 assert(ret.out == b.data() + b.size()); 483 } 484 // binary 485 { 486 int b[] = {2, 5, 4, 3, 1}; 487 std::array<int, 5> c; 488 std::same_as<std::ranges::in_in_out_result<std::ranges::dangling, int*, int*>> auto ret = 489 std::ranges::transform(std::array{1, 2, 3, 5, 4}, b, c.data(), [](int i, int j) { return i * j; }); 490 assert((c == std::array{2, 10, 12, 15, 4})); 491 assert(ret.in2 == b + 5); 492 assert(ret.out == c.data() + c.size()); 493 } 494 { 495 int a[] = {2, 5, 4, 3, 1, 4, 5, 6}; 496 std::array<int, 8> c; 497 std::same_as<std::ranges::in_in_out_result<int*, std::ranges::dangling, int*>> auto ret = 498 std::ranges::transform(a, std::array{1, 2, 3, 5, 4, 5, 6, 7}, c.data(), [](int i, int j) { return i * j; }); 499 assert((c == std::array{2, 10, 12, 15, 4, 20, 30, 42})); 500 assert(ret.in1 == a + 8); 501 assert(ret.out == c.data() + c.size()); 502 } 503 { 504 std::array<int, 3> c; 505 std::same_as<std::ranges::in_in_out_result<std::ranges::dangling, std::ranges::dangling, int*>> auto ret = 506 std::ranges::transform(std::array{4, 4, 4}, std::array{4, 4, 4}, c.data(), [](int i, int j) { return i * j; }); 507 assert((c == std::array{16, 16, 16})); 508 assert(ret.out == c.data() + c.size()); 509 } 510 } 511 512 { // check that returning another type from the projection works 513 { // unary 514 { 515 struct S { int i; int other; }; 516 S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} }; 517 std::array<int, 4> b; 518 std::ranges::transform(a, a + 4, b.begin(), [](S s) { return s.i; }); 519 assert((b == std::array{0, 1, 3, 10})); 520 } 521 { 522 struct S { int i; int other; }; 523 S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} }; 524 std::array<int, 4> b; 525 std::ranges::transform(a, b.begin(), [](S s) { return s.i; }); 526 assert((b == std::array{0, 1, 3, 10})); 527 } 528 } 529 { // binary 530 { 531 struct S { int i; int other; }; 532 S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} }; 533 S b[] = { S{0, 10}, S{1, 20}, S{3, 30}, S{10, 40} }; 534 std::array<int, 4> c; 535 std::ranges::transform(a, a + 4, b, b + 4, c.begin(), [](S s1, S s2) { return s1.i + s2.other; }); 536 assert((c == std::array{10, 21, 33, 50})); 537 } 538 { 539 struct S { int i; int other; }; 540 S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} }; 541 S b[] = { S{0, 10}, S{1, 20}, S{3, 30}, S{10, 40} }; 542 std::array<int, 4> c; 543 std::ranges::transform(a, b, c.begin(), [](S s1, S s2) { return s1.i + s2.other; }); 544 assert((c == std::array{10, 21, 33, 50})); 545 } 546 } 547 } 548 549 { // check that std::invoke is used 550 { // unary 551 struct S { int i; }; 552 S a[] = { S{1}, S{3}, S{2} }; 553 std::array<int, 3> b; 554 auto ret = std::ranges::transform(a, b.data(), [](int i) { return i; }, &S::i); 555 assert((b == std::array{1, 3, 2})); 556 assert(ret.out == b.data() + 3); 557 } 558 { // binary 559 struct S { int i; }; 560 S a[] = { S{1}, S{3}, S{2} }; 561 S b[] = { S{2}, S{5}, S{3} }; 562 std::array<int, 3> c; 563 auto ret = std::ranges::transform(a, b, c.data(), [](int i, int j) { return i + j + 2; }, &S::i, &S::i); 564 assert((c == std::array{5, 10, 7})); 565 assert(ret.out == c.data() + 3); 566 } 567 } 568 569 return true; 570 } 571 572 int main(int, char**) { 573 test_iterators_in1_in2<cpp17_output_iterator<int*>>(); 574 test_iterators_in1_in2<cpp20_output_iterator<int*>>(); 575 test_iterators_in1_in2<forward_iterator<int*>>(); 576 test_iterators_in1_in2<bidirectional_iterator<int*>>(); 577 test_iterators_in1_in2<random_access_iterator<int*>>(); 578 test_iterators_in1_in2<contiguous_iterator<int*>>(); 579 test_iterators_in1_in2<int*>(); 580 test(); 581 static_assert(test()); 582 583 return 0; 584 } 585