Comment fonctionne la gamme basée sur le travail pour les tableaux simples?

En C ++ 11, vous pouvez utiliser une plage basée for , qui agit comme foreach des autres langages. Cela fonctionne même avec des tableaux C simples:

 int numbers[] = { 1, 2, 3, 4, 5 }; for (int& n : numbers) { n *= 2; } 

Comment sait-il quand arrêter? Ne fonctionne-t-il qu’avec des tableaux statiques déclarés dans la même scope que dans for ? Comment utiliseriez-vous cela avec les tableaux dynamics?

Cela fonctionne pour toute expression dont le type est un tableau. Par exemple:

 int (*arraypointer)[4] = new int[1][4]{{1, 2, 3, 4}}; for(int &n : *arraypointer) n *= 2; delete [] arraypointer; 

Pour une explication plus détaillée, si le type de l’expression passée à droite de : est un type tableau, la boucle effectue une itération de ptr à ptr + size ( ptr pointant vers le premier élément du tableau, size étant le nombre d’éléments de le tableau).

Cela contraste avec les types définis par l’utilisateur, qui fonctionnent en regardant begin et end tant que membres si vous passez un object de classe ou (s’il n’y a pas de membre appelé ainsi) des fonctions non-membres. Ces fonctions donneront les iterators de début et de fin (pointant directement après le dernier élément et le début de la séquence respectivement).

Cette question clarifie pourquoi cette différence existe.

Je pense que la partie la plus importante de cette question est la suivante: comment C ++ sait-il quelle est la taille d’un tableau (du moins, je voulais le savoir quand j’ai trouvé cette question).

C ++ connaît la taille d’un tableau, car il fait partie de la définition du tableau – c’est le type de la variable. Un compilateur doit connaître le type.

Depuis C ++ 11, std::extent peut être utilisé pour obtenir la taille d’un tableau:

 int size1{ std::extent< char[5] >::value }; std::cout << "Array size: " << size1 << std::endl; 

Bien sûr, cela n'a pas beaucoup de sens, car vous devez fournir explicitement la taille dans la première ligne, que vous obtenez ensuite dans la deuxième ligne. Mais vous pouvez aussi utiliser decltype et ensuite ça devient plus intéressant:

 char v[] { 'A', 'B', 'C', 'D' }; int size2{ std::extent< decltype(v) >::value }; std::cout << "Array size: " << size2 << std::endl; 

Selon la dernière version de travail C ++ (n3376), l’instruction rangeed est la suivante:

 { auto && __range = range-init; for (auto __begin = begin-expr, __end = end-expr; __begin != __end; ++__begin) { for-range-declaration = *__begin; statement } } 

Donc, il sait comment arrêter de la même manière que for iterators classiques.

Je pense que vous pourriez chercher quelque chose comme ce qui suit pour fournir un moyen d’utiliser la syntaxe ci-dessus avec des tableaux composés uniquement d’un pointeur et d’une taille (tableaux dynamics):

 template  class Range { public: Range(T* collection, size_t size) : mCollection(collection), mSize(size) { } T* begin() { return &mCollection[0]; } T* end () { return &mCollection[mSize]; } private: T* mCollection; size_t mSize; }; 

Ce modèle de classe peut ensuite être utilisé pour créer une plage sur laquelle vous pouvez effectuer une itération à l’aide de la nouvelle syntaxe. Je l’utilise pour parcourir tous les objects d’animation d’une scène imscope à l’aide d’une bibliothèque qui renvoie uniquement un pointeur vers un tableau et une taille en tant que valeurs séparées.

 for ( auto pAnimation : Range(pScene->mAnimations, pScene->mNumAnimations) ) { // Do something with each pAnimation instance here } 

A mon avis, cette syntaxe est beaucoup plus claire que ce que vous obtiendriez en utilisant std::for_each ou une plaine for boucle.

Il sait quand arrêter car il connaît les limites des tableaux statiques.

Je ne suis pas sûr de ce que vous entendez par “tableaux dynamics”, dans tous les cas, si vous ne parcourez pas les tableaux statiques de manière informelle, le compilateur recherche les noms begin et end dans la scope de l’object parcouru, ou recherche pour begin(range) et end(range) utilisant une recherche dépendante des arguments et les utilise comme iterators.

Pour plus d’informations, dans la norme C ++ 11 (ou son ébauche publique), “6.5.4 L’énoncé basé for intervalles”, p.

Comment fonctionne la gamme basée sur le travail pour les tableaux simples?

Est-ce que cela doit se lire comme suit: ” Dites-moi ce que fait un jeu à distance (avec des tableaux)?

Je vais répondre en supposant que – Prenez l’exemple suivant en utilisant des tableaux nesteds:

 int ia[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; for (auto &pl : ia) 

Version texte:

ia est un tableau de tableaux (“tableau nested”), contenant [3] tableaux, chacun contenant [4] valeurs. L’exemple ci-dessus boucle ia par son ‘range’ primaire ( [3] ), et donc les boucles [3] fois. Chaque boucle produit l’une des [3] premières valeurs de ia commençant par la première et se terminant par la dernière – Un tableau contenant des valeurs [4] .

  • Première boucle: pl est égal à {1,2,3,4} – Un tableau
  • Deuxième boucle: pl est égal à {5,6,7,8} – Un tableau
  • Troisième boucle: pl est égal à {9,10,11,12} – Un tableau

Avant d’expliquer le processus, voici quelques rappels amicaux sur les tableaux:

  • Les tableaux sont interprétés comme des pointeurs vers leur première valeur – L’utilisation d’un tableau sans aucune itération renvoie l’adresse de la première valeur
  • pl doit être une référence car nous ne pouvons pas copier les tableaux
  • Avec les tableaux, lorsque vous ajoutez un nombre à l’object tableau, il avance plusieurs fois et pointe vers l’entrée équivalente – Si n est le nombre en question, alors ia[n] est identique à *(ia+n) (Nous sums en train de déréférencer l’adresse vers l’avant), et ia+n est identique à &ia[n] (nous obtenons l’adresse de cette entrée dans le tableau).

Voici ce qui se passe:

  • Sur chaque boucle, pl est défini comme une référence à ia[n] , n égal au compte de boucle courant à partir de 0. Donc, pl est ia[0] au premier tour, au second ia[1] , et bientôt. Il récupère la valeur via une itération.
  • La boucle se poursuit tant que ia+n est inférieur à end(ia) .

… Et c’est à peu près tout.

C’est vraiment une façon simple d’écrire ceci :

 int ia[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; for (int n = 0; n != 3; ++n) auto &pl = ia[n]; 

Si votre tableau n’est pas nested, alors ce processus devient un peu plus simple car une référence n’est pas nécessaire, car la valeur itérée n’est pas un tableau mais une valeur «normale»:

  int ib[3] = {1,2,3}; // short for (auto pl : ib) cout << pl; // long for (int n = 0; n != 3; ++n) cout << ib[n]; 

Quelques informations supplémentaires

Et si nous ne voulions pas utiliser le mot auto clé auto lors de la création de pl ? A quoi cela ressemblerait-il?

Dans l'exemple suivant, pl fait référence à un array of four integers . Sur chaque boucle, pl reçoit la valeur ia[n] :

 int ia[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; for (int (&pl)[4] : ia) 

Et ... Voilà comment cela fonctionne, avec des informations supplémentaires pour éliminer toute confusion. C'est juste un raccourci for boucle qui compte automatiquement pour vous, mais ne permet pas de récupérer la boucle actuelle sans la faire manuellement.