2009-05-14 14 views
6

È possibile definire 2 variabili dello stesso tipo in un ciclo for:Esiste un modo per definire le variabili di due tipi diversi in un inizializzatore del ciclo for?

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

ma è illegale per definire le variabili di diverse tipologie:

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

C'è un modo per fare questo? (Non ho bisogno di usare i all'interno del ciclo, solo j.)

Se hai una soluzione totalmente compromessa e oscura, per me va bene.

In questo esempio inventato so che è possibile utilizzare solo double per entrambe le variabili. Sto cercando una risposta generale.

Si prega di non suggerire di spostare nessuna delle variabili al di fuori del corpo, probabilmente non utilizzabile per me poiché uno è un iteratore che deve scomparire subito dopo il ciclo e l'istruzione for deve essere inclusa nella 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;           \ 
    }            \ 
    } 

può essere utilizzato in tal modo:

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

Ma ho bisogno di qualcosa che verrà utilizzato come quella:

foreach(ii, collection) 
    cout << ii; 

Si prega di non introdurre alcun sovraccarico di runtime (ma potrebbe essere lento compilare).

+1

Ti rendi conto che ci potrebbe non essere una soluzione che soddisfi tutte le condizioni che hai dato? –

+6

"Per favore non suggerire di spostare nessuna delle variabili al di fuori del corpo, probabilmente non usabile per me perché l'iteratore deve scomparire subito dopo il ciclo." Sembra che tu abbia creato un requisito artificiale. Ciò che ti interessa è la portata dell'iteratore, non se è nel corpo del for. Cerca di spiegare * solo * le tue esigenze senza aggiungere le tue nozioni preconcette riguardo all'ambito dell'ambito. Sarà più facile per le persone capire il tuo problema e aiutarti. – dss539

+3

ogni volta che qualcuno trova una soluzione, aggiungi un "Per favore non dire ....." e commenta "non utile ... cambia corpo ...." Perché lo fai ?? –

risposta

9

Ecco una versione con spinta preprocessore (Questo è solo per divertimento Per la risposta del mondo reale, vedere @ propria cucina sopra.):

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

} 

La prima parte specifica una sequenza di dichiarazioni: (a)(b).... Le variabili dichiarate in seguito possono fare riferimento a variabili dichiarate prima di esse. La seconda e la terza parte sono come al solito. Quando le virgole si verificano nella seconda e nella terza parte, è possibile utilizzare le parentesi per impedire che vengano separate le macro argomentazioni.

Esistono due trucchi noti per dichiarare variabili che sono successivamente visibili in un'istruzione composta aggiunta all'esterno di una macro. Il primo utilizza condizioni, come un se:

if(int k = 0) ; else COMPOUND_STATEMENT 

Quindi k è visibile. Naturalmente, deve sempre essere valutato a false. Quindi non può essere usato da noi. L'altro contesto è questo:

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

Questo è quello che ho intenzione di usare qui. Dovremo guardare per fare solo un'iterazione di COMPOUND_STATEMENT. Il ciclo effettivo for che esegue il controllo di incremento e condizione deve venire alla fine, quindi l'istruzione composta aggiunta lo soddisfa.

#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; 
    } 
} 

E 'la creazione di un gruppo di for dichiarazioni, ogni annidati in un altro.Si espande in:

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

Esattamente quello di cui avevo bisogno. Grazie –

+0

Si scopre che prima se e due per/s vengono ottimizzati. –

24

Si prega di non suggerire di spostare qualsiasi variabili al di fuori del corpo per, probabilmente non utilizzabile per me come l'iteratore deve sparire subito dopo il ciclo.

Si potrebbe fare questo:

#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

Batti a me per secondi! –

+0

Anch'io, e anche con più codice boilerplate! :) – Reunanen

+0

Purtroppo non utile –

0

Perché non basta dichiarare e inizializzare le variabili al di fuori del ciclo for? Puoi ancora testare e incrementare come lo hai ora.

+0

Perché l'istruzione verrà utilizzata nella macro. –

+0

Bene, c'è il tuo problema. I macro sono intrinsecamente imperfetti e pericolosi e si imbattono in condizioni che non possono gestire. Del resto, si è spesso avvitati perché le macro non comprendono i modelli con virgole. Rinuncia alla macro, tutti i problemi vanno via. –

+0

Come molti hanno già menzionato, è sufficiente racchiudere l'espressione in un nuovo ambito {..}. Pozdrawiam. –

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

Le variabili "scompaiono" dopo il blocco.

+1

Questo è l'approccio canonico per la creazione di variabili all'interno di macro. –

6

Questo renderà l'iteratore (o in questo caso, float) scompaiono quando è più necessario:

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

Beh, è ​​brutto. Ma potresti usare la coppia.

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

Bella idea! E poi generalizzare a più di due tipi usando boost :: tuple. – Reunanen

+0

bella idea ma costringe a cambiare il corpo del loop, quindi non posso accettarlo –

+3

Volevo rispondere con boost :: tupla, ma mi hai battuto :) Ma perché no per (std :: coppia p (0 , 0.0f); p.first <10; p.first ++, p.second = 2 * p.first) {...}? –

2

Si prega di non suggerire di spostare qualsiasi delle variabili al di fuori del per il corpo, probabilmente non utilizzabile per me come l'iteratore deve sparire subito dopo il ciclo.

Si potrebbe ancora farlo e mettere il tutto in parentesi graffe per fare in modo che la variabile extra esca dallo scope.

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

In questo modo j sarebbe fuori portata subito dopo il ciclo.

2

Con i requisiti che danno il codice più semplice mi viene in mente è:

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

Si utilizza solo f come il doppio del valore di i. La vita è limitata al ciclo e (almeno nella domanda semplificata che fornisci) i float sono economici da creare (esattamente come economici da assegnare).

Se la costruzione del reale galleggiante (sto supponendo che poiché i non è realmente un int, f non può essere un float o) è molto più costoso rispetto riassegnando il valore, poi le altre soluzioni di incapsulare all'interno di un la coppia migliore di parentesi graffe per limitare l'ambito sarebbe l'opzione migliore.

+0

Argh! Sconfiggilo di * un * secondo! (secondo SO) – Reunanen

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

Forse sono un po 'denso, ma perché devi dichiarare il galleggiante? Devi solo "buttarlo via" quando lasci comunque il ciclo. Destra?

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

Perché hai bisogno di j?

1

Dite che il i è il vostro tipo e dovete solo generare j su i, giusto? Facile. Aggiungere una funzione membro alla classe i per generare il valore j e utilizzarlo sempre. Probabilmente puoi anche fare una macro per "nascondere" la chiamata a quella funzione membro, se vuoi. :-)

6

Se hai problemi con le macro, c'è uno standard do..while trucco che funziona perfettamente:

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

usarlo come segue:

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

E 'brutto, ma lo fa ciò che si desidera: l'ambito di i e j è limitato dal ciclo do..while dalla macro e alla fine richiede un punto e virgola, quindi non verrà morso inserendolo nel predicato di un'istruzione if/else.

+0

Questo è il migliore con cui sono arrivato. Ma ho bisogno che il corpo sia separato dalla macro. –

4

MODIFICA: la domanda è cambiata ancora una volta. La domanda ora vuole esplicitamente implementare un ciclo foreach. La risposta più semplice:

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

iniezione di una variabile in un blocco di codice

Questo non è inteso come una risposta, ma per mostrare una tecnica più generale per l'iniezione di una variabile in un blocco di codice. Sembra che la macro che l'OP sta tentando di definire potrebbe utilizzare, anche se si incorre in alcuni overhead

Ci sono un paio di punti in cui è possibile definire una variabile con diversi ambiti. È possibile definire una variabile all'interno di qualsiasi blocco di codice e la sua durata sarà alla fine di quel particolare blocco.È possibile definire una variabile tra parentesi di un ciclo for e l'ambito sarà il blocco del ciclo. Puoi anche definire una variabile all'interno di un blocco if e il suo ambito sarà quello del if (inclusa la clausola else).

È possibile combinare le suddette opzioni per creare esternamente e iniettare variabili in un blocco di codice senza creare una variabile la cui durata superiore a quella del blocco. . Un esempio pratico sarebbe quello di definire un ciclo foreach (semplificato lavorare solo su contenitori STL La sintassi chiamata sarebbe:

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

Con semantica simile a foreach in altre lingue: x viene fatto riferimento a ciascun elemento del contenitore, cosicché la funzione effettivamente raddoppia ogni valore all'interno del vettore intero

Ora il codice della macro semplificata:.

#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) 

Generalizzando la macro per ogni contenitore e tipo richiede alcuni metaprogrammazione che cade su t lui contesto della domanda, ma l'idea di come funziona (spero) non dovrebbe essere troppo difficile da seguire.

Gli esterni per itera il contenitore, in ogni iterazione eseguiamo un'altra per sola volta definendo la variabile iterazione (int & x nel codice di esempio). Abbiamo bisogno di una condizione per controllare il numero di iterazioni (1) del ciclo interno e tale condizione viene iniettata con un se. Scegliamo di fare il fail in modo che possiamo garantire che l'utente non ottenga risultati imprevisti se scrive un altro dopo il ciclo ... i macro sono difficili.

5

Questo è anche brutto, ma fornisce anche un modo generale per la dichiarazione delle variabili multiple con un dato nome e tipi in 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 soluzione creativa :-) –

+0

Questa soluzione sembra funzionare solo con gcc, non VS 2010 ... – Gob00st