2009-05-14 32 views
6

Puede definir 2 variables del mismo tipo en un bucle for:¿Hay alguna manera de definir variables de dos tipos diferentes en un inicializador for loop?

int main() { 
    for (int i = 0, j = 0; i < 10; i += 1, j = 2*i) { 
    cout << j << endl; 
    } 
} 

pero es ilegal para definir las variables de diferentes tipos:

int main() { 
    for (int i = 0, float j = 0.0; i < 10; i += 1, j = 2*i) { 
    cout << j << endl; 
    } 
} 

¿Hay una manera de hacer esto? (No necesito usar i dentro del ciclo, solo j.)

Si tiene una solución totalmente pirateada y oscura, está bien para mí.

En este ejemplo ideado, sé que podría usar double para ambas variables. Estoy buscando una respuesta general.

Por favor, no sugiera mover ninguna de las variables fuera del cuerpo, probablemente no se pueda usar ya que una es un iterador que debe desaparecer justo después del bucle y la instrucción para se debe encerrar en mi macro foreach:

#define foreach(var, iter, instr) {     \ 
    typeof(iter) var##IT = iter;      \ 
    typeof(iter)::Element var = *var##IT;   \ 
    for (; var##_iterIT.is_still_ok(); ++var##IT, var = *var#IT) { \ 
     instr;           \ 
    }            \ 
    } 

se puede utilizar así:

foreach(ii, collection, { 
    cout << ii; 
}). 

pero necesito algo que va a ser utilizado como esa:

foreach(ii, collection) 
    cout << ii; 

No introduzca ninguna sobrecarga de tiempo de ejecución (pero puede tardar en compilarse).

+1

¿Se da cuenta de que podría ¿No habrá ninguna solución que satisfaga todas las condiciones que has dado? –

+6

"No sugiero que mueva ninguna de las variables fuera del cuerpo, probablemente no se pueda usar porque el iterador debe desaparecer justo después del bucle". Parece que ha creado un requisito artificial. Lo que más te importa es el alcance del iterador, no si está en el cuerpo del for. Intente explicar * solo * sus requisitos sin agregar sus nociones preconcebidas sobre el alcance. Será más fácil para las personas entender su problema y ayudarlo. – dss539

+3

cada vez que alguien presenta una solución, agrega un "Por favor, no diga ....." y comente "no es útil ... cambia de cuerpo ..." ¿Por qué lo hace? –

Respuesta

9

Aquí es una versión utilizando impulso preprocesador (Esto es sólo por diversión Para la respuesta del mundo real, ver @ uno de cocina arriba.):

FOR((int i = 0)(int j = 0.0), i < 10, (i += 1, j = 2 * i)) { 

} 

La primera parte especifica una secuencia de declaraciones: (a)(b).... Las variables declaradas posteriormente pueden referirse a las variables declaradas antes de ellas. La segunda y tercera parte son como de costumbre. Cuando aparecen comas en la segunda y tercera partes, se pueden usar paréntesis para evitar que separen los argumentos de macro.

Se conocen dos trucos para declarar las variables que luego son visibles en una sentencia compuesta agregada fuera de una macro. La primera usa condiciones, como un if:

if(int k = 0) ; else COMPOUND_STATEMENT 

Luego k es visible. Naturalmente, siempre tiene que evaluar a false. Entonces no puede ser usado por nosotros. El otro contexto es este:

for(int k = 0; ...; ...) COMPOUND_STATEMENT 

Eso es lo que voy a usar aquí. Tendremos que mirar para hacer solo una iteración de COMPOUND_STATEMENT. El ciclo real for que realiza el incremento y la verificación de condición tiene que venir al final, por lo que la declaración compuesta adjunta pertenece a él.

#include <boost/preprocessor.hpp> 
#include <iostream> 

#define EMIT_DEC_(R,D,DEC) \ 
    for(DEC; !_k;) 

#define FOR(DECS, COND, INC) \ 
    if(bool _k = false) ; else \ 
     BOOST_PP_SEQ_FOR_EACH(EMIT_DEC_, DECS, DECS) \ 
     for(_k = true; COND; INC) 

int main() { 
    FOR((int i = 0)(float j = 0.0f), i < 10, (i += 1, j = 2 * i)) { 
     std::cout << j << std::endl; 
    } 
} 

Se trata de crear un montón de for declaraciones, cada uno anidado en otro.Se expande en:

if(bool _k = false) ; else 
    for(int i = 0; !_k;) 
    for(float j = 0.0f; !_k;) 
     for(_k = true; i < 10; (i += 1, j = 2 * i)) { 
     std::cout << j << std::endl; 
     } 
+0

Exactamente lo que necesitaba. Gracias –

+0

Resulta que primero si y dos for/s están optimizados. –

24

Por favor, no sugieren para mover cualquiera de las variables fuera del cuerpo para, probablemente no utilizable para mí como el iterador tiene que desaparecer justo después el bucle.

Usted puede hacer esto:

#include <iostream> 

int main(int, char *[]) { 
    { 
     float j = 0.0; 

     for (int i = 0; i < 10; i += 1, j = 2*i) { 
      std::cout << j << std::endl; 
     } 
    } 

    float j = 2.0; // works 

    std::cout << j << std::endl; 

    return 0; 
} 
+0

¡Sume a esto por segundos! –

+0

¡Yo también, e incluso con más código repetitivo! :) – Reunanen

+0

Desgraciadamente no útil –

0

¿Por qué no acaba de declarar e inicializar las variables fuera del bucle? Todavía puede probar e incrementar como lo tiene ahora.

+0

Porque la instrucción para se utilizará en macro. –

+0

Bueno, ahí está tu problema. Las macros son intrínsecamente defectuosas y peligrosas y te encuentras con condiciones que no pueden manejar. Para el caso, a menudo se atornilla porque las macros no entienden las plantillas con comas. Renunciar a la macro, todos sus problemas desaparecen. –

+0

Como muchos ya han mencionado, simplemente encierre su expresión dentro de un nuevo alcance {..}. Pozdrawiam. –

7
{ 
    int i = 0; 
    float j = 0.0; 
    for (; i < 10; i += 1, j = 2*i) { 
    cout << j << endl; 
    } 
} 

Las variables "desaparecen" después del bloque.

+1

Este es el enfoque canónico para crear variables dentro de las macros. –

6

Esto hará que el iterador (o en este caso, flotador) desaparecerá cuando es más necesario:

int main() { 
    // some code... 

    { 
    float j = 0.0; 
    for (int i = 0; i < 10; i += 1, j = 2*i) { 
     cout << j << endl; 
    } 
    } 

    // more code... 
} 
10

Bueno, es feo. Pero podrías usar par.

int main() { 
    for (std::pair<int,float> p(0,0.0f); 
     p.first < 10; 
     p.first += 1, p.second = 2*p.first) { 
    cout << p.second << endl; 
    } 
} 
+1

¡Buena idea! Y luego generalice a más de dos tipos usando boost :: tuple. – Reunanen

+0

buena idea pero obliga a cambiar el cuerpo del bucle, por lo que no puedo aceptarlo –

+3

Quería responder con boost :: tuple, pero me ganaste :) Pero ¿por qué no para (std :: pair p (0 , 0.0f); p.first <10; p.first ++, p.second = 2 * p.first) {...}? –

2

Por favor, no sugieren para mover ninguna de las variables fuera del cuerpo para, probablemente no utilizable para mí como el iterador tiene que desaparecer justo después del bucle.

Aún puede hacer eso, y poner todo en llaves para que la variable extra salga del alcance.

int main() 
{ 
    { 
    float j = 0.0; 
    for (int i = 0; i < 10; i += 1, j = 2*i) 
    { 
     cout << j << endl; 
    } 
    } 
    // more code... 
} 

De esta manera j iría fuera de alcance justo después del bucle.

2

con los requisitos que dan el código más simple que puedo pensar es:

for (int i = 0; i < 10; ++i) 
{ 
    float f = i * 2; 
    std::cout << f << std::endl; 
} 

sólo utiliza f como el doble del valor de i . La duración se limita al ciclo y (al menos en la pregunta simplificada que proporciona) los flotantes son baratos de crear (exactamente tan baratos como asignarlos).

Si la construcción de lo real flotador (Estoy asumiendo que ya que no es realmente un int, f no puede ser un flotador tampoco) es mucho más caro que reasignar el valor, entonces las otras soluciones de encapsular dentro de una un par extra de llaves para limitar el alcance sería la mejor opción.

+0

Argh! ¡Pásame por * un * segundo! (de acuerdo con SO) – Reunanen

1
int main() { 
    for (int i = 0, float j = 0.0; i < 10; i += 1, j = 2*i) { 
    cout << j << endl; 
    } 
} 

Tal vez estoy siendo denso, pero ¿por qué incluso tienes que declarar el flotador? Simplemente "tíralo" cuando de todos modos salgas del lazo. ¿Derecha?

for(int i=0; i<10; ++i) 
    cout << (float)2*i << endl; 

¿Por qué usted necesita j?

1

Usted dice que i es su propio tipo, y solo necesita generar j de i, ¿verdad? Fácil. Agregue una función de miembro a la clase i para generar el valor j y utilícelo siempre. Probablemente pueda incluso crear una macro para "ocultar" la llamada a esa función miembro, si lo desea. :-)

6

Si tienes problemas con macros, hay una norma do..while truco que funciona a la perfección:

#define MYFOR(init, test, post, body) \ 
    do \ 
    { \ 
     init \ 
     for(; test; post) \ 
      body \ 
    } while(0) 

utilizarlo como sigue:

MYFOR(int i = 0; float j = 0.0f; , i < 10 , (i += 1, j = 2.0f * i), 
    { 
     cout << j << endl; 
    }); 

Es feo, pero lo hace lo que desea: el alcance de i y j está limitado por el bucle do..while de la macro, y requiere un punto y coma al final, por lo que no lo picarán poniéndolo en el predicado de una instrucción if/else.

+0

Este es el mejor con el que vine. Pero necesito cuerpo para estar separado de macro. –

4

EDIT: La pregunta ha cambiado una vez más. La pregunta ahora explícitamente quiere implementar un ciclo foreach. La respuesta más simple:

#include <boost/foreach.hpp> 
void(std::vector<int>& v) { 
    BOOST_FOREACH(int & x, v) { 
     x = x*2; 
    } 
} 

La inyección de una variable en un bloque de código

Esto no pretende ser una respuesta, sino para mostrar una técnica más general para inyectar una variable en un bloque de código. Parece como si la macro que OP intenta definir pudiera usar, incluso si incurre en alguna sobrecarga

Hay un par de lugares donde puede definir una variable con diferentes ámbitos. Puede definir una variable dentro de cualquier bloque de código, y su vida útil será hasta el final de ese bloque en particular.Puede definir una variable en el paréntesis de un ciclo for y el alcance será el bloque de ciclo. También puede definir una variable dentro de un bloque if y su alcance será el de if (incluida la cláusula else).

Puede combinar las opciones anteriores para crear de forma externa e insertar variables en un bloque de código sin crear una variable cuya vida útil exceda la del bloque. . Un ejemplo práctico sería definir un bucle foreach (simplificado para trabajar sólo en contenedores STL La sintaxis de llamada sería:

void f(std::vector<int>& container) 
{ 
    INTVECTOR_FOREACH(int & x, container) 
    { 
     x = x*2; 
    } 
} 

Con semántica similar a foreach en otros idiomas: x se hace referencia a cada elemento en el recipiente, de modo que la función se duplica cada valor dentro del vector entero

Ahora el código de la macro simplificado:.

#define INTVECTOR_FOREACH(variable, container) \ 
    for (std::vector<int>::iterator it = container.begin(); it!=container.end(); ++it) \ 
     if (bool condition=false) {} else \ 
     for (variable = *it; !condition; condition=true) 

Generalizando la macro para cualquier recipiente y el tipo requiere un poco de metaprogramming que cae de t El contexto de la pregunta, pero la idea de cómo funciona (espero) no debería ser demasiado difícil de seguir.

Las externos para itera sobre el recipiente, en cada iteración que ejecutar otro para sólo una vez que define la variable de iteración (int & x en el código de ejemplo). Necesitamos una condición para controlar el número de iteraciones (1) del ciclo interno, y esa condición se inyecta con un si. Elegimos hacer el error si para que podamos garantizar que el usuario no obtenga resultados inesperados si escribe un else después del bucle ... las macros son complicadas.

5

Este también es feo, pero ofrece también alguna manera general para declarar múltiples variables con un nombre determinado y tipos en un ciclo for

int main() { 
    for (struct { int i; float j; } x = { }; 
     x.i < 10; x.i += 1, x.j = 2 * x.i) { 
    cout << x.j << endl; 
    } 
} 
+0

+1 solución creativa :-) –

+0

Esta solución parece funcionar solo con gcc, no VS 2010 ... – Gob00st

Cuestiones relacionadas