Spec-Zone.ru › C++

std::ranges::for_each, std::ranges::for_each_result

Определён в заголовочном файле <algorithm>
Сигнатура вызова
template< std::input_iterator I, std::sentinel_for<I> S,
          class Proj = std::identity,
          std::indirectly_unary_invocable<std::projected<I, Proj>> Fun >
constexpr for_each_result<I, Fun>
    for_each( I first, S last, Fun f, Proj proj = {} );
(1) (начиная с C++20)
template< ranges::input_range R, class Proj = std::identity,
          std::indirectly_unary_invocable
              <std::projected<ranges::iterator_t<R>, Proj>> Fun >
constexpr for_each_result<ranges::borrowed_iterator_t<R>, Fun>
    for_each( R&& r, Fun f, Proj proj = {} );
(2) (начиная с C++20)
template< /*execution-policy*/ Ep, std::random_access_iterator I,
          std::sized_sentinel_for<I> S, class Proj = std::identity,
          std::indirectly_unary_invocable<std::projected<I, Proj>> Fun >
I for_each( Ep&& policy, I first, S last, Fun f, Proj proj = {} );
(3) (начиная с C++26)
template< /*execution-policy*/ Ep,
          /*sized-random-access-range*/ R, class Proj = std::identity,
          std::indirectly_unary_invocable
              <std::projected<ranges::iterator_t<R>, Proj>> Fun >
ranges::borrowed_iterator_t<R>
    for_each( Ep&& policy, R&& r, Fun f, Proj proj = {} );
(4) (начиная с C++26)
Вспомогательные типы
template< class I, class F >
using for_each_result = ranges::in_fun_result<I, F>;
(5) (начиная с C++20)

Определение /*execution-policy*/ см. на этой странице; определение /*sized-random-access-range*/ см. на этой странице.

Применяет заданный вызываемый объект f к каждому элементу (преобразованному с помощью proj) целевого диапазона [first, last) или r. Если f возвращает результат, он игнорируется.

1,2) f применяется по порядку, начиная с начала целевого диапазона.
3,4) f может применяться не по порядку. Алгоритм выполняется в соответствии с policy.
В отличие от других параллельных алгоритмов, for_each не может произвольно создавать копии элементов целевого диапазона.

Описанные на этой странице функциональные объекты алгоритмов (неформально известные как неблойды), то есть:

  • При их вызове нельзя указывать явные списки аргументов шаблона.
  • Ни один из них не виден для поиска, зависящего от аргументов.
  • Если какой-либо из них найден с помощью обычного неквалифицированного поиска как имя слева от оператора вызова функции, поиск, зависящий от аргументов, подавляется.

Параметры

first, last - пара итераторов, задающая целевой диапазон
r - целевой диапазон
f - вызываемый объект, применяемый к элементам (после преобразования)
proj - проекция, применяемая к элементам
policy - политика выполнения

Возвращаемое значение

1) {last, std::move(f)}
2) {ranges::next(ranges::begin(r), ranges::end(r)), std::move(f)} если R моделирует forward_range, иначе (начиная с C++26){ranges::end(r), std::move(f)}
3) last
4) ranges::next(ranges::begin(r), ranges::end(r)) если R моделирует forward_range, иначе (начиная с C++26)ranges::end(r)

Сложность

1,3) Ровно ranges::distance(first, last) применений f и proj.
2,4) Ровно ranges::distance(r) применений f и proj.

Исключения

3,4) Во время выполнения:
  • Если временные ресурсы памяти, необходимые для распараллеливания, недоступны, выбрасывается std::bad_alloc.
  • Если при доступе к объектам через аргумент алгоритма выбрасывается необработанное исключение, поведение определяется политикой выполнения (для стандартных политик вызывается std::terminate).

Примечания

Если проекция возвращает изменяемую ссылку, f может изменить элементы целевого диапазона.

Для перегрузок (1,2) f может быть вызываемым объектом с состоянием. Вызываемый объект в возвращаемом значении можно рассматривать как итоговое состояние пакетной операции.

Для перегрузок (3,4) для параллельного вызова может быть создано несколько копий f. Возвращаемое значение не содержит вызываемый объект, поскольку параллелизация часто не позволяет эффективно накапливать состояние.

Возможная реализация

struct for_each_fn
{
    template<std::input_iterator I, std::sentinel_for<I> S, class Proj = std::identity,
             std::indirectly_unary_invocable<std::projected<I, Proj>> Fun>
    constexpr ranges::for_each_result<I, Fun>
        operator()(I first, S last, Fun f, Proj proj = {}) const
    {
        for (; first != last; ++first)
            std::invoke(f, std::invoke(proj, *first));
        return {std::move(first), std::move(f)};
    }
    
    template<ranges::input_range R, class Proj = std::identity,
             std::indirectly_unary_invocable
                 <std::projected<ranges::iterator_t<R>, Proj>> Fun>
    constexpr ranges::for_each_result<ranges::borrowed_iterator_t<R>, Fun>
        operator()(R&& r, Fun f, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r), ranges::end(r), std::move(f), std::ref(proj));
    }
    
    template<ranges::forward_range R, class Proj = std::identity,
             std::indirectly_unary_invocable
                 <std::projected<ranges::iterator_t<R>, Proj>> Fun>
    constexpr ranges::for_each_result<ranges::borrowed_iterator_t<R>, Fun>
        operator()(R&& r, Fun f, Proj proj = {}) const
    {
        return (*this)(ranges::begin(r),
                       ranges::next(ranges::begin(r), ranges::end(r)),
                       std::move(f), std::ref(proj));
    }
};

inline constexpr for_each_fn for_each;

Пример

В следующем примере используется лямбда-выражение, чтобы увеличить все элементы вектора, а затем перегруженный operator() в вызываемом объекте, чтобы вычислить их сумму. Обратите внимание: для вычисления суммы рекомендуется использовать специальный алгоритм std::accumulate.

#include <algorithm>
#include <cassert>
#include <iostream>
#include <string>
#include <utility>
#include <vector>

struct Sum
{
    void operator()(int n) { sum += n; }
    int sum {0};
};

int main()
{
    namespace ranges = std::ranges;
    
    std::vector<int> nums {3, 4, 2, 8, 15, 267};
    
    auto print = [](const auto& n) { std::cout << ' ' << n; };
    
    std::cout << "before:";
    ranges::for_each(std::as_const(nums), print);
    print('\n');
    
    ranges::for_each(nums, [](int& n) { ++n; });
    
    // calls Sum::operator() for each number
    auto [i, s] = ranges::for_each(nums.begin(), nums.end(), Sum());
    assert(i == nums.end());
    
    std::cout << "after: ";
    ranges::for_each(nums.cbegin(), nums.cend(), print);
    
    std::cout << "\n" "sum: " << s.sum << '\n';
    
    using pair = std::pair<int, std::string>; 
    std::vector<pair> pairs {{1,"one"}, {2,"two"}, {3,"tree"}};
    
    std::cout << "project the pair::first: ";
    ranges::for_each(pairs, print, [](const pair& p) { return p.first; });
    
    std::cout << "\n" "project the pair::second:";
    ranges::for_each(pairs, print, &pair::second);
    print('\n');
}

Вывод:

before: 3 4 2 8 15 267 
after:  4 5 3 9 16 268
sum: 305
project the pair::first:  1 2 3
project the pair::second: one two tree

См. также

for_each
применяет унарный функциональный объект к элементам диапазона
(шаблон функции)
ranges::for_each_n
(C++20)
применяет функциональный объект к первым N элементам последовательности
(функциональный объект алгоритма)
ranges::transform
(C++20)
применяет функцию к диапазону элементов
(функциональный объект алгоритма)
цикл range-for(C++11) выполняет цикл по диапазону

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/ranges/for_each

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API