◐ Shell
clean mode source ↗

std::ranges::for_each_n, std::ranges::for_each_n_result - cppreference.com

De cppreference.com

Definido en el archivo de encabezado <algorithm>

Signatura de la llamada

template< std::input_iterator I, class Proj = identity, std::indirectly_unary_invocable<std::projected<I, Proj>> Fun > constexpr for_each_n_result<I, Fun> for_each_n( I first, std::iter_difference_t<I> n, Fun f, Proj proj = {});

(1) (desde C++20)

Tipos auxiliares

template< class I, class F > using for_each_n_result = ranges::in_fun_result<I, F>;

(2) (desde C++20)

1) Aplica el objeto función dado f al resultado proyectado por proj de desreferenciar cada iterador en el rango [first, first + n), en orden.

Si el tipo de iterador es mutable, f puede modificar los elementos del rango a través del iterador desreferenciado. Si f devuelve un resultado, el resultado se ignora. Si n es menor que cero, el comportamiento no está definido.

Las entidades similares a funciones descritas en esta página son niebloids, es decir:

En la práctica, pueden implementarse como objetos función o con extensiones de compilador especiales.

Parámetros

first - Iterador que denota el comienzo del rango al que aplicar la función.
n - el número de elementos a los que aplicar la función.
f - La función a aplicar al rango proyectado [first, first + n).
proj - Proyección a aplicar a los elementos.

Valor de retorno

Un objeto {first + n, std::move(f)}, donde first + n puede evaluarse como std::ranges::next(std::move(first), n) dependiendo de la categoría del iterador.

Complejidad

Exactamente n aplicaciones de f y proj.

Notas

La sobrecarga en namespace::ranges requiere que Fun modele copy_constructible.

Posible implementación

struct for_each_n_fn {
  template<std::input_iterator I, class Proj = std::identity,
           std::indirectly_unary_invocable<std::projected<I, Proj>> Fun>
    constexpr for_each_n_result<I, Fun>
      operator()(I first, std::iter_difference_t<I> n, Fun fun, Proj proj = Proj{}) const
      {
        for (; n-- > 0; ++first) {
          std::invoke(fun, std::invoke(proj, *first));
        }
        return {std::move(first), std::move(fun)};
      }
};

inline constexpr for_each_n_fn for_each_n{};

Ejemplo

#include <algorithm>
#include <array>
#include <iostream>
#include <ranges>
#include <string_view>

struct P {
    int primero; char segundo;
    friend std::ostream& operator<< (std::ostream& os, const P& p) {
        return os << '{' << p.primero << ",'" << p.segundo << "'}";
    }
};

auto imprimir = [](std::string_view nombre, auto const& v) {
    std::cout << nombre << ": ";
    for (auto n = v.size(); const auto& e: v) {
        std::cout << e << (--n ? ", " : "\n");
    }
};

int main()
{
    std::array a{1, 2, 3, 4, 5};
    imprimir("a", a);
    // Negar los tres primeros números:
    std::ranges::for_each_n(a.begin(), 3, [](auto& n) { n *= -1; });
    imprimir("a", a);

    std::array s{ P{1,'a'}, P{2, 'b'}, P{3, 'c'}, P{4, 'd'} };
    imprimir("s", s);
    // Negar los datos miembro 'P::primero' usando proyección:
    std::ranges::for_each_n(s.begin(), 2, [](auto& x) { x *= -1; }, &P::primero);
    imprimir("s", s);
    // Capitalizar los datos miembro 'P::segundo' usando proyección:
    std::ranges::for_each_n(s.begin(), 3, [](auto& c) { c -= 'a'-'A'; }, &P::segundo);
    imprimir("s", s);
}

Salida:

a: 1, 2, 3, 4, 5
a: -1, -2, -3, 4, 5
s: {1,'a'}, {2,'b'}, {3,'c'}, {4,'d'}
s: {-1,'a'}, {-2,'b'}, {3,'c'}, {4,'d'}
s: {-1,'A'}, {-2,'B'}, {3,'C'}, {4,'d'}

Véase también