while usando tutorialspoint tipos terminar suma resueltos programas programar numeros for estructura enum ejercicios ejemplos contador con como ciclos ciclo bucle acumulador c++ for-loop c++11

c++ - usando - tipos de bucle for



EnumeraciĆ³n de bucle tipo Python en C++ (3)

Posible duplicado:
Encontrar la posición del elemento en C ++ 11 en función del rango para el ciclo

Tengo un vector y me gustaría iterarlo y, al mismo tiempo, tener acceso a los índices para cada elemento individual (necesito pasar tanto el elemento como su índice a una función). He considerado las siguientes dos soluciones:

std::vector<int> v = { 10, 20, 30 }; // Solution 1 for (std::vector<int>::size_type idx = 0; idx < v.size(); ++idx) foo(v[idx], idx); // Solution 2 for (auto it = v.begin(); it != v.end(); ++it) foo(*it, it - v.begin());

Me preguntaba si podría haber una solución más compacta. Algo similar a la enumerate de Python. Esto es lo más cercano que tengo usando un bucle de rango C ++ 11, pero tener que definir el índice fuera del ciclo en un ámbito privado definitivamente parece ser una solución peor que 1 o 2:

{ int idx = 0; for (auto& elem : v) foo(elem, idx++); }

¿Hay alguna forma (tal vez usando Boost) para simplificar el último ejemplo de tal manera que el índice se autocontenga en el ciclo?


Aquí hay algún tipo de solución divertida que usa la evaluación perezosa. Primero, construye el objeto generador enumerate_object :

template<typename Iterable> class enumerate_object { private: Iterable _iter; std::size_t _size; decltype(std::begin(_iter)) _begin; const decltype(std::end(_iter)) _end; public: enumerate_object(Iterable iter): _iter(iter), _size(0), _begin(std::begin(iter)), _end(std::end(iter)) {} const enumerate_object& begin() const { return *this; } const enumerate_object& end() const { return *this; } bool operator!=(const enumerate_object&) const { return _begin != _end; } void operator++() { ++_begin; ++_size; } auto operator*() const -> std::pair<std::size_t, decltype(*_begin)> { return { _size, *_begin }; } };

A continuación, cree una enumeración de función de envoltura que deducirá los argumentos de la plantilla y devolverá el generador:

template<typename Iterable> auto enumerate(Iterable&& iter) -> enumerate_object<Iterable> { return { std::forward<Iterable>(iter) }; }

Ahora puede usar su función de esa manera:

int main() { std::vector<double> vec = { 1., 2., 3., 4., 5. }; for (auto&& a: enumerate(vec)) { size_t index = std::get<0>(a); double& value = std::get<1>(a); value += index; } }

La implementación anterior es un mero juguete: debería funcionar tanto con referencias de valores const como no const , así como con referencias rvalue, pero tiene un costo real para este último, considerando que copia todo el objeto repetible varias veces. Este problema seguramente podría resolverse con ajustes adicionales.

Desde C ++ 17, las declaraciones de descomposición incluso le permiten tener la sintaxis similar a Python para nombrar el índice y el valor directamente en el inicializador:

int main() { std::vector<double> vec = { 1., 2., 3., 4., 5. }; for (auto&& [index, value] a: enumerate(vec)) { value += index; } }

No tengo a mano un compilador compatible con C ++ 17 para verificarlo, pero espero que el auto&& en la descomposición pueda inferir el index como std::size_t y el value como double& .


Como dice @Kos, esto es algo tan simple que realmente no veo la necesidad de simplificarlo aún más y personalmente me limitaría al tradicional ciclo for con índices, excepto que abandonaría std::vector<T>::size_type y simplemente use std::size_t :

for(std::size_t i = 0; i < v.size(); ++i) foo(v[i], i);

No estoy muy interesado en la solución 2. Requiere iteradores de acceso aleatorio (un poco ocultos) que no le permiten intercambiar fácilmente el contenedor, que es uno de los puntos fuertes de los iteradores. Si desea utilizar iteradores y hacerlo genérico (y posiblemente incurrir en un golpe de rendimiento cuando los iteradores no son de acceso aleatorio), le recomiendo usar std::distance :

for(auto it(v.begin()); it != v.end(); ++it) foo(*it, std::distance(it, v.begin());


Una forma es envolver el bucle en una función propia.

#include <iostream> #include <vector> #include <string> template<typename T, typename F> void mapWithIndex(std::vector<T> vec, F fun) { for(int i = 0; i < vec.size(); i++) fun(vec[i], i); } int main() { std::vector<std::string> vec = {"hello", "cup", "of", "tea"}; mapWithIndex(vec, [](std::string s, int i){ std::cout << i << " " << s << ''/n''; } ); }