//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // UNSUPPORTED: c++03, c++11, c++14, c++17 // template S, class Proj = identity, // indirectly_unary_invocable> Fun> // constexpr ranges::for_each_result // ranges::for_each(I first, S last, Fun f, Proj proj = {}); // template, Proj>> Fun> // constexpr ranges::for_each_result, Fun> // ranges::for_each(R&& r, Fun f, Proj proj = {}); #include #include #include #include "almost_satisfies_types.h" #include "test_iterators.h" struct Callable { void operator()(int); }; template concept HasForEachIt = requires (Iter iter, Sent sent) { std::ranges::for_each(iter, sent, Callable{}); }; static_assert(HasForEachIt); static_assert(!HasForEachIt); static_assert(!HasForEachIt); static_assert(!HasForEachIt); static_assert(!HasForEachIt); static_assert(!HasForEachIt); template concept HasForEachItFunc = requires(int* a, int* b, Func func) { std::ranges::for_each(a, b, func); }; static_assert(HasForEachItFunc); static_assert(!HasForEachItFunc); static_assert(!HasForEachItFunc); template concept HasForEachR = requires (Range range) { std::ranges::for_each(range, Callable{}); }; static_assert(HasForEachR>); static_assert(!HasForEachR); static_assert(!HasForEachR); static_assert(!HasForEachR); static_assert(!HasForEachR); static_assert(!HasForEachR); template concept HasForEachRFunc = requires(UncheckedRange a, Func func) { std::ranges::for_each(a, func); }; static_assert(HasForEachRFunc); static_assert(!HasForEachRFunc); static_assert(!HasForEachRFunc); template constexpr void test_iterator() { { // simple test { auto func = [i = 0](int& a) mutable { a += i++; }; int a[] = {1, 6, 3, 4}; std::same_as> decltype(auto) ret = std::ranges::for_each(Iter(a), Sent(Iter(a + 4)), func); assert(a[0] == 1); assert(a[1] == 7); assert(a[2] == 5); assert(a[3] == 7); assert(base(ret.in) == a + 4); int i = 0; ret.fun(i); assert(i == 4); } { auto func = [i = 0](int& a) mutable { a += i++; }; int a[] = {1, 6, 3, 4}; auto range = std::ranges::subrange(Iter(a), Sent(Iter(a + 4))); std::same_as> decltype(auto) ret = std::ranges::for_each(range, func); assert(a[0] == 1); assert(a[1] == 7); assert(a[2] == 5); assert(a[3] == 7); assert(base(ret.in) == a + 4); int i = 0; ret.fun(i); assert(i == 4); } } { // check that an empty range works { std::array a = {}; std::ranges::for_each(Iter(a.data()), Sent(Iter(a.data())), [](auto&) { assert(false); }); } { std::array a = {}; auto range = std::ranges::subrange(Iter(a.data()), Sent(Iter(a.data()))); std::ranges::for_each(range, [](auto&) { assert(false); }); } } } constexpr bool test() { test_iterator, sentinel_wrapper>>(); test_iterator, sentinel_wrapper>>(); test_iterator>(); test_iterator>(); test_iterator>(); test_iterator>(); test_iterator(); { // check that std::invoke is used struct S { int check; int other; }; { S a[] = {{1, 2}, {3, 4}, {5, 6}}; std::ranges::for_each(a, a + 3, [](int& i) { i = 0; }, &S::check); assert(a[0].check == 0); assert(a[0].other == 2); assert(a[1].check == 0); assert(a[1].other == 4); assert(a[2].check == 0); assert(a[2].other == 6); } { S a[] = {{1, 2}, {3, 4}, {5, 6}}; std::ranges::for_each(a, [](int& i) { i = 0; }, &S::check); assert(a[0].check == 0); assert(a[0].other == 2); assert(a[1].check == 0); assert(a[1].other == 4); assert(a[2].check == 0); assert(a[2].other == 6); } } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }