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