Utilisation de la variable déclarée dans une boucle for basée sur une plage

Dans l’exemple ci-dessous, i une scope de fonction. Mais il semble que je ne puisse pas utiliser i dans la seconde pour la boucle. Pourquoi for (i : v1) ne fonctionne pas, mais for (int i : v1) fonctionne?

 #include #include #include int main() { std::vector v1; int i; while(std::cin>>i) { v1.push_back(i); } for(i : v1) //for (int i:v1) works std::cout<<i<<"\t"; cout<<std::endl; return 0; } 

C’est un problème de syntaxe qu’une boucle basée for une plage nécessite une déclaration d’une variable nommée , c’est-à-dire qu’elle nécessite un spécificateur de type (cf., par exemple, cppreference.com ):

pour (range_declaration: range_expression) loop_statement

range_declaration – déclaration d’une variable nommée dont le type est le type de l’élément de la séquence représenté par range_expression ou une référence à ce type. Utilise souvent le spécificateur automatique pour la déduction automatique de type

En fait, je ne sais pas pourquoi votre question a été rejetée; Je trouve votre hypothèse assez correcte; juste la syntaxe C ++ a décidé de la définir autrement.

Le range-based for est spécifiquement destiné à remplacer les boucles qui s’apparentent à la suivante (il s’agit d’un cas quelque peu simpliste, basé for plages, en particulier la version C ++ 17, est plus général que l’exemple):

 for (auto it = range.begin(), end = range.end(); it != end; ++it) { use(*it); } 

Dans la majorité des cas, n’utilisera pas les valeurs aux différents emplacements, mais utilisera plutôt l’élément à l’emplacement même:

  1. Lors de la mutation des éléments dans la séquence, une valeur n’aide pas vraiment.
  2. Dans la plupart des cas, copier les valeurs est coûteux et conserver une référence est plus efficace.
  3. Il existe même des cas où les objects ne peuvent pas être copiés pour commencer.

En conséquence, les concepteurs de systèmes basés for gamme ont décidé que les références devaient absolument être sockets en charge. Dans le même temps, il était prévu d’utiliser une règle de réécriture raisonnablement simpliste pour une base basée for une plage. La règle qui est codifiée dans la norme est la suivante:

 for (: ) {  } 

est équivalent à

 { auto&& range = ; // keep the range alive! auto it = begin(range); // actually, reality is bit more complicated auto end = end(range); // actually, reality is a bit more complicated for (; it != end; ++it) {  = *it; // this is the rewrite causing your issue  } } 

En particulier, est une déclaration plutôt que de simplement nommer une variable. La raison de cette exigence est que généralement, l’entité utilisée devant le : est une référence. Cependant, les références ne peuvent pas être rebondies. Cependant, à chaque itération d’une boucle, une nouvelle référence peut être utilisée.

En principe, la règle de réécriture pourrait fonctionner avec des affectations si le n’est pas une déclaration mais plutôt une lvalue. Cela donnerait sa propre part de comportements bizarres:

  • Il y aurait une différence entre for (T const& x: range) et T const& x = 0; for (x: range) T const& x = 0; for (x: range) : le premier fonctionne alors que le second est une erreur.
  • Si la lvalue est une référence à un object situé quelque part ( T& x = get_reference(); for (x: range) {...} ), la boucle affecterait automatiquement toutes les valeurs d’une plage à un object situé quelque part. Normalement, les objects sont situés dans la stack ou dans la plage source (lorsque la variable est déclarée comme référence).

Il était plus raisonnable d’autoriser les initialisations que de prendre en charge l’initialisation ou les affectations en fonction de la manière dont la variable est déclarée. L’ examen de l’historique de révision des propositions ( N2930 et prédécesseurs) ne donne pas lieu à une discussion, mais je me rappelle vaguement que ce point a été discuté.

Lorsque vous utilisez des boucles basées sur des plages, vous avez besoin d’une déclaration après avoir ouvert les parenthèses, pas seulement une variable. La syntaxe correcte est la suivante:

  for ( declaration : range ) statement; 

Vous pouvez voir ce lien pour plus d’informations.

Dans votre exemple : lorsque vous déclarez i avant votre boucle while, vous pouvez l’utiliser dans toute la fonction main et sa scope est la fonction main . Vous pouvez l’utiliser dans cela for corps. Lorsque vous utilisez la variable i dans votre plage for alors vous ne la déclarez pas, car vous l’avez déjà déclarée ci-dessus, elle vous donnera donc une erreur et ce n’est pas correct avec la syntaxe C ++.

Mais quand vous tapez int avant le i dans votre parenthèse, vous déclarez une autre variable avec le nom de i , mais seulement pour votre boucle for et ensuite, elle est correcte avec la syntaxe C ++.

La raison en est probablement que cela impliquerait des assignations de copie sur la variable, ce qui deviendrait une source potentielle de grande inefficacité et, en pratique, ne serait presque jamais l’intention … si le type prend en charge la copie.
Donc, ils ont probablement pensé qu’il était préférable d’interdire cela.