2010-08-09 6 views
16

Possible en double:
In C++ why can’t I write a for() loop like this: for(int i = 1, double i2 = 0; …Pourquoi est-il si «difficile» d'écrire une boucle forcée en C++ avec 2 variables de boucle?

développeur AC écrirait ceci:

int myIndex; 
for (myIndex=0;myIndex<10;++myIndex) ... 

Un développeur C++ écrira ceci pour empêcher la variable de boucle de fuir à l'extérieur de la boucle:

for (int myIndex=0;myIndex<10;++myIndex) ... 

Cependant, si vous avez 2 variables de boucle, vous ne pouvez plus le faire. Ce qui suit ne compile pas:

for (int myIndex=0,MyElement *ptr=Pool->First;ptr;++myIndex,ptr=ptr->next) ... 

L'opérateur virgule ne permet pas à deux variables à définir de cette façon, donc nous devons l'écrire comme ceci:

int myIndex; 
MyElement *ptr; 
for (myIndex=0,ptr=Pool->First;ptr;++myIndex,ptr=ptr->next) ... 

qui contrecarre l'avantage d'avoir vraies variables locales en boucle.

Une solution pourrait être de mettre toute la construction entre accolades, comme ceci:

{ 
int myIndex; 
MyElement *ptr; 
for (myIndex=0,ptr=Pool->First;ptr;++myIndex,ptr=ptr->next) ... 
} 

Mais cela est à peine plus élégant.

N'y a-t-il pas une meilleure façon de le faire en C++ (ou C++ 0x)?

+1

Pourquoi un programmeur C mettre nécessairement la variable au-dessus de la boucle? – GManNickG

+7

@GMan La déclaration à l'intérieur de l'instruction for n'est valide que depuis C99, IIRC – Wim

+7

@Wim: Qui était il y a 11 ans. :) – GManNickG

Répondre

23

Vous devez juste comprendre la première déclaration est une déclaration (et cette virgule est pas l'opérateur de virgule). Il est pas plus difficile à faire:

for (int i, double d; ...) 

Than est:

int i, double d; 

Parce que for (init cond; expr) statement obtient étendu à:

{ 
    init 
    while (cond) 
    { 
     statement 
     expr; 
    } 
} 

Une astuce est de faire que init déclaration une définition struct et par exemple, comme:

for (struct { int myIndex; MyElement* ptr;} data = {0, Pool->First}; 
    data.ptr; 
    ++data.myIndex, data.ptr = data.ptr->next) 
    { 
     // blah... 
    } 

qui devient le même que:

{ 
    struct 
    { 
     int myIndex; 
     MyElement* ptr; 
    } data = {0, Pool->First}; 

    while (data.ptr) 
    { 
     { 
      // blah... 
     } 
     ++data.myIndex, data.ptr = data.ptr->next; 
    } 
} 

Mais je trouve que assez laid. En pratique, je le diviserais comme vous l'avez fait. Si la portée est vraiment un problème, ce qui n'est probablement pas, jeter les accolades supplémentaires là-bas.

Je ne pense pas qu'il y ait beaucoup à améliorer ici sans un peu de code standard.

+2

Oh c'est une solution laide, je suis plutôt content de ne pas y avoir pensé. :-) Moi aussi je préfère mettre la boucle dans son propre bloc. – Omnifarious

+0

Réponse acceptée. Il ne semble pas y avoir de manière plus élégante que de définir les variables en dehors de la boucle for et de placer le bloc entier entre les accolades. – Patrick

+3

+1 pour sortir des sentiers battus! Mais oui, moche! :-) –

2

au moins C++ nous permet de déclarer des variables dans le si clause, qui est parfois utilisé pour déclarer une variable qui est seulement visible que lorsque une condition est vraie:

if (MyElement *ptr=Pool->First) // block is only entered when ptr!=0 
{ 
for (int myIndex=0;ptr;++myIndex,ptr=ptr->next) 
{ 
} 
} 
// ptr is out of scope now. 

Cela pourrait être un méthode pour limiter la portée de ptr et d'index, tout en maintenant la lisibilité.

+0

Il n'y a vraiment pas besoin de l'instruction if. Vous pouvez ajouter des accolades (presque) partout où vous souhaitez créer une nouvelle portée. –

+0

Le motif 'if() for() ...' fonctionne également avec les macros. –

8

Si je voulais vraiment limiter la portée à la boucle j'utiliser:

#include <utility> 
for (auto i = std::make_pair(0,Pool->First); 
    i.second; 
    ++i.first, i.second=i.second->next) 
+0

Mais maintenant vous perdez toutes les informations fournies par les noms de variables: 'i.first' et' i.second' ne fournissent aucune information sur le but des variables, alors que 'myIndex' et' ptr' en donnent (pas beaucoup, mais certains). –

+2

Oui, il y a un compromis à faire ici - je dirais que c'est le compromis standard en utilisant la paire. Si le but des membres de la paire est évident, je m'en tiendrai à la paire. Sinon, je passerais à une solution avec des noms explicites. –

+0

@LucTouraille: vous pouvez toujours définir une petite structure pour cela à la place de std :: pair <> .. – lorro