2010-11-23 5 views
9

En C++ cambiar una variable de bucle dentro de un bucle para se permite:¿Cómo mostrar que una variable de control de bucle no está modificada dentro del cuerpo for-loop de C++?

for(int i = 0; i < limit; i++) { 
    if(condition) { 
     i--; 
    } 
} 

Ahora bien, si un cuerpo del bucle es bastante complejo no es inmediatamente obvio para el lector si la variable de bucle se cambia dentro del bucle cuerpo. Sería bueno modificar el código de alguna manera para que, una vez que el lector solo vea el encabezado for-loop, sepa inmediatamente que la variable de bucle no ha cambiado dentro del cuerpo.

Por ejemplo, si uso const:

const int value = computeValue(); 
//lots of code here 

entonces es claro que todo lo que está escrito el código debajo de la definición de la variable const la variable no se ha modificado.

¿Hay alguna manera de lograr algo similar - constness lógica dentro de la iteración - en el caso de las variables de control for-loop en C++?

+3

Creo que 'std :: for_each' podría hacer esto. – kennytm

+0

Utilicé 'BOOST_FOREACH' con gran éxito. Incluso puede introducir una conveniencia '#define foreach BOOST_FOREACH' en su encabezado precompilado. –

Respuesta

1

No hay ninguna construcción lógica para hacer cumplir esto. Si coloca 'const int idx = i' como la primera instrucción en el ciclo, y luego solo usa 'idx', es posible que pueda lograr una imposición similar pero a pérdida de cierta claridad. De lo contrario, solo usa comentarios.

0

Puede intentar cambiar su nombre de variable de "bucle" por algo largo y ridículo, de modo que al tocarlo dentro del bucle (más de una vez) se raspare el ojo.

También me gusta usar macros de bucle dedicadas, como BOOST_FOREACH. Esto oculta la variable de bucle/iterador.

4

No creo que esto sea posible para el bucle hecho a mano, pero supongo que podría considerarse un argumento adicional para alentar el uso de std::for_each y BOOST_FOREACH para iteraciones sobre el contenedor STL.

EDITAR ... y el C++ 0x range-based for-loop (gracias Matthieu. M :)

+0

+1, ¡mucho mejor y más limpio que la forma en que lo hice! :) –

+0

Si se desea garantizar la no modificación del contador de bucles dentro del cuerpo del bucle, entonces por el amor de Dios * solo hazlo *. Mostré una forma en mi respuesta, hay otros. Pero no hagas esta cosa de Rube Goldberg que ni siquiera logra el propósito. –

+0

@Alf: obviamente, como lo indican las etiquetas de "solución estúpida" en mi respuesta, nunca recomendaría algo así en el código "real" – icecrime

2

Esta es una gran pregunta y me hizo pensar en cómo se puede hacer esto y maneras alrededor de él. Sin tener que gastar demasiado tiempo, lo único que se me ocurrió fue:

int limit = 10; 
for(int i(0), guard(0); i < limit; i++, guard++) 
{ 
     // lots of code here 
    assert(i == guard); 
} 

Obviamente, el usuario podría modificar la guardia en el circuito, pero tal vez el inention en la parte superior muestra que se va a comprobar.

1

Técnicamente, podría hacerlo, p.

int main() 
{ 
    for(int i = 0; i < 42; ++i) 
    {{ 
     typedef void i; 

     i = 666;  // !Nope. 
    }} 
} 

Si desea acceder a i en el interior del cuerpo del bucle, a continuación, tendría que proporcionar un nombre alternativo (en referencia a const) antes de la typedef.

Pero no recomiendo esta solución técnica, porque es oscura y no es común, por lo que no es obvia para el lector.

En su lugar, simplemente refactorice los bucles grandes.:-)

1

Puede hacer que todo el cuerpo del bucle for sea una función separada, para la cual la variable de control de bucle está fuera del alcance.

No se me ocurre una forma sencilla de hacer lo que quiere ya que la variable de control de bucle es mutable a la definición, para controlar el bucle.

2

C++ 0x diversión. Este código no se compila:

 
for (int i = 0; i < 10; ++i) 
{ 
    [&, i]() 
    { 
     if (i == 5) 
     { 
      ++i; 
     } 
     cout << i << endl; 
    }(); 
} 

error: 'i': un subproducto de la captura de valor no se puede modificar en un lambda no mutable

2

Uso for_each combina con boost::counting_iterator y una función que acepta un const En t.

for_each(boost::counting_iterator<int>(0), boost::counting_iterator<int>(limit), 
    [&](const int i) 
    { 
     // do something with i 
    }); 
+0

Creo que con C++ 0x, puede hacer eso ' typedef boost :: counting_iterator bcii; for (const int i: std :: make_pair (bcii (0), bcii (limit))) {...} ' –

1

crear un objeto extraño con un macro que toma ARCHIVO y LÍNEA, este último posiblemente como un parámetro de plantilla (¿es una constante de tiempo de compilación?). A medida que la incremente, debe usar el mismo ARCHIVO y LÍNEA. Bueno, la misma línea probablemente sea suficiente. Si no está en la misma línea, es posible que obtenga un error de compilación.

template< int line > 
class Counter 
{ 
// stuff 
public: 
    bool valid() const; 
    static void inc(Counter<line> & counter); 
}; 

for(Counter<__LINE__> counter(n); counter.valid(); Counter<__LINE__>::inc(counter)) 
{ 
// body 

    // what __LINE__ do I need to use here to increment counter? Can be done but won't be 
} 

No he probado el. Solo una idea.

Cuestiones relacionadas