2 votes

La boucle for(auto) dans la fonction print génère une erreur, pourquoi ?

El for boucle dans main compile bien mais dans la fonction d'impression, il ne le fait pas, avec le diagnostique

for(auto i:x) cout<<i<<" ";        

  -----------^std::end  
'end' was not declared in this scope; did you mean 'std::end'?

en cours d'émission. Voici le code complet :

#include <iostream>
void print(int x[],int n)
{
   for(auto i:x) std::cout<<i<<" ";
}

int main()
{
    int arr[] = {1, 5, 2, 1, 4, 3, 1, 7, 2, 8, 9, 5};
    int n = sizeof(arr) / sizeof(int);
    for(auto i:arr)
        std::cout<<i<<" ";
    print(arr, n);
    return 0;
}

2voto

Bathsheba Points 23209

Le problème est que le tableau arr se désintègre à un pointeur lorsqu'il est passé à la fonction print . Le mécanisme qui sous-tend l'approche for se fait par l'utilisation de std::begin y std::end . Cela explique en partie le diagnostic du compilateur : il ne fonctionne pas s'il est appliqué à des types pointeurs.

Cette dégradation des pointeurs est le comportement normal lors du passage de paramètres de tableaux à des fonctions, mais n'est en aucun cas universel. Par exemple, std::begin y std::end permettent d'éviter ce problème grâce à une astuce de template (sinon ils seraient inutiles pour les types de tableaux), ce que vous pouvez également faire en écrivant

template<typename T>
void print(T&& x, int n)
{
   for(auto i:x) std::cout<<i<<" ";
}

à la place.

1voto

einpoklum Points 2893

La réponse de @schorsch312 est correcte, mais la suggestion d'avoir la print() prend un std::vector n'est pas la "méthode C++" : Utilisation de std::vector au lieu d'un simple tableau dans votre programme principal est très bien, mais lors de l'écriture d'une fonction - je recommanderais de ne pas prendre un type plus spécifique que ce dont vous avez réellement besoin pour effectuer le travail de la fonction, et spécifiquement de ne pas allouer de la mémoire sur le tas avec un nouveau vecteur.

Dans le cas où vous avez un tableau C dans votre programme, la suggestion de @Bathsheba d'un print() est meilleur à mon avis, dans la mesure où il permettra vous permet de passer le tableau tel quel, et donc de l'itérer correctement.

Cependant - pour des raisons pédagogiques, je vous suggère de considérer cette version print() :

template <std::size_t N>
void print(const int (&arr)[N]) {
    for(auto i : arr) {
       std::cout << i << " ";
    }
}

qui illustre comment print() peut prendre une référence de tableau. Vous avez besoin du modèle lorsque vous ne connaissez pas la taille du tableau apriori. (et ceci fonctionne également bien sûr.)

Vous pouvez également utiliser l'algorithme de la bibliothèque standard, std::for_each comme ça :

#include <vector>
#include <iostream>
#include <algorithm>

int main()
{
    int arr[] {1, 5, 2, 1, 4, 3, 1, 7, 2, 8, 9, 5};
    for(auto i:arr) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
    std::for_each(
        std::begin(arr), std::end(arr),
        [](auto i) { std::cout << i << ' '; }
    );
}

Notez que lorsque vous utilisez la boucle "rangé-pour", ce qui se passe est en fait l'équivalent de la fonction for_each ou d'une boucle for brute sur un itérateur commençant à l'adresse std::begin(arr) et se terminant à std::end(arr) .

Une autre solution - qui ne nécessite pas de se préoccuper des paires d'itérateurs - consiste à disposer d'un fichier print() qui prend un span ( Qu'est-ce qu'un "span" et quand dois-je l'utiliser ? ). Ici, cela a un certain sens puisqu'un tableau C ordinaire peut être désigné par un span : Il possède un stockage d'éléments contigus et une longueur spécifique. Si vous utilisiez C++20, votre fonction print utilisant un span ressemblerait à ceci :

#include <span> 

void print(const std::span<int> &sp) {
    for(auto i : sp) {
       std::cout << i << ' ';
    }
}

et encore une fois, vous n'avez pas besoin de spécifier la longueur dans votre fonction principale. Le C++14 n'a pas de spans dans la bibliothèque standard, mais la bibliothèque de support des directives C++ (cf. ici o ici ) l'a, comme gsl::span - et il fonctionne en C++14.


Les points faibles :

  • Il n'est pas nécessaire de return 0 de main() - qui se fait automatiquement.
  • Veuillez utiliser des espaces entre #include et les crochets (c'est-à-dire les directives #include <foo> pas #include <foo> .
  • Veuillez utiliser des espaces avant et après << opérateurs.
  • Pour imprimer un espace, vous n'avez pas besoin d'une chaîne de caractères ; le caractère espace unique suffit, c'est-à-dire std::cout << ' ' plutôt que std::cout << " " .

1voto

schorsch312 Points 2628

Le bon vieux type de données int[] ne possède pas de end-iterator si vous le passez à une fonction. Dans ce cas, il suffit de passer un pointeur sur le premier élément. Pour utiliser une boucle for basée sur l'intervalle, vous devez utiliser un conteneur de données, qui a un itérateur de début et de fin, tel que std::vector

Aquí Votre code est dans un format plus C++ manière.

#include<vector>
#include<iostream>

void print(const std::vector<int> &x) {
    for(auto i:x) {
       std::cout<<i<<" ";
    }
}

int main() {
    const std::vector<int> arr {1, 5, 2, 1, 4, 3, 1, 7, 2, 8, 9, 5};
    for(auto i:arr) {
        std::cout << i << " ";
    }

    print(arr);
    return 0;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X