c++ - tube - sentencia for en c
Índice de acceso en el rango de bucle for (4)
Tengo un vector de objetos y estoy iterando a través de él usando un bucle de rango para. Lo estoy usando para imprimir una función desde el objeto, como esto:
vector<thisObject> storedValues;
//put stuff in storedValues
for(auto i:storedValues)
{
cout<<i.function();
}
Pero también quiero imprimir el índice. Mi salida deseada es:
1: value
2: value
//etc
Iba a usar un contador que aumentaba cada vez, pero eso parecía muy ineficiente. ¿Hay alguna manera mejor?
Estoy seguro de que a algunas personas no les gustará esto, pero he creado una macro de preprocesador que maneja esto por usted de una manera relativamente limpia (IMO):
#define indexed(...) indexed_v(i, __VA_ARGS__)
#define indexed_v(v, ...) (bool _i_ = true, _break_ = false; _i_;) for(size_t v = 0; _i_; _i_ = false) for(__VA_ARGS__) if(_break_) break; else for(bool _j_ = true; _j_;) for(_break_ = true; _j_; _j_ = false) for(bool _k_ = true; _k_; v++, _k_ = false, _break_ = false)
Ejemplo de uso:
std::vector<int> v {1, 2, 3};
for indexed (const auto& item : v) {
if (i > 0) std::cout << ", ";
std::cout << i << ": " << item;
}
Para usar una variable de bucle diferente:
for indexed_v (my_cool_counter, const auto& item : v) ...
Lo he comprobado dos -O1
y todo este extra se optimiza lejos en -O1
o superior. Te quedas con una sintaxis de bucle agradable y fácil de leer.
Bonificación: esto funciona también en los bucles de estilo iterator
clásico.
Actualización 28/05/2017 : break;
hecho break;
las declaraciones funcionan correctamente
Honestamente, es bastante simple, solo tengo que descubrir que puedes restar direcciones :)
& i hará referencia a la dirección en la memoria, y se incrementará en 4 de índice a índice porque es un entero del tipo de vector definido. Ahora y los valores [0] hacen referencia al primer punto, cuando reste las 2 direcciones, la diferencia entre las dos será 0,4,8,12 respetuosamente, pero en realidad está restando el tamaño del tipo entero, que suele ser de 4 bytes. Entonces, en la correspondencia 0 = 0th int, 4 = 1st int, 8 = 2nd int, 12 = 3rd int
Aquí está en un vector.
vector<int> values = {10,30,9,8};
for(auto &i: values) {
cout << "index: " << &i - &values[0];
cout << "/tvalue: " << i << endl;
}
Aquí está para una matriz regular, más o menos lo mismo
int values[]= {10,30,9,8};
for(auto &i: values) {
cout << "index: " << &i - &values[0];
cout << "/tvalue: " << i << endl;
}
Tenga en cuenta que esto es para C ++ 11, si está usando g ++, recuerde usar el parámetro -std = c ++ 11 para compilar
Usted no puede El índice es una noción específica de un vector y no una propiedad genérica de una colección. El bucle basado en rango, por otro lado, es un mecanismo genérico para iterar sobre cada elemento de cualquier colección.
Si desea usar los detalles de la implementación de su contenedor en particular, solo use un ciclo ordinario:
for (std::size_t i = 0, e = v.size(); i != e; ++i) { /* ... */ }
Para repetir el punto: los bucles basados en rango son para manipular cada elemento de cualquier colección, donde la colección en sí no importa, y el contenedor nunca se menciona dentro del cuerpo del bucle. Es solo otra herramienta en tu caja de herramientas, y no estás obligado a usarla para absolutamente todo. Por el contrario, si desea mutar la colección (por ejemplo, eliminar o barajar elementos), o usar información específica sobre la estructura de la colección, use un bucle ordinario.
Utilice range-v3
. Range-v3
es la biblioteca de rango de próxima generación diseñada e implementada por Eric Niebler, miembro del Comité de ISO C ++, y se espera que se fusione en el estándar de C ++ en el futuro.
Usando el problema de range-v3
OP se puede resolver fácilmente:
using ranges::v3::view::zip;
using ranges::v3::view::ints;
for(auto &&[i, idx]: zip(storedValues, ints(0u))){
std::cout << idx << ": " << i.function() << ''/n'';
}
Necesitará un compilador compatible con C ++ 17 o posterior para compilar este fragmento de código, no solo para la sintaxis de enlace estructurado , sino también para el hecho de que el tipo de retorno de la función de begin
y end
para el valor de retorno de ranges::v3::view::zip
difiere.
Puedes ver el ejemplo en línea here . La documentación de range-v3
está here y el código fuente en sí está alojado here . También puede echar un vistazo here si está utilizando compiladores de MSVC.