56 votes

Boucles FOR améliorées en C++

Je passe de Java à C++ et je me demandais si C++ contient les boucles for améliorées que j'utilisais en Java, par exemple :

int[] numbers = {1,2,3,4,5,6,7,8,9,10};
for (int item : numbers) {
  System.out.println("Count is: " + item);
}

Ce même "raccourci" est-il possible en C++ ?

73voto

pmr Points 30450

C++11 le fait. Ils sont appelés fors basés sur l'intervalle. Rappelez-vous que vous devez qualifier le type comme étant une référence ou une référence à const.

La solution de contournement pour C++03 est BOOST_FOR_EACH o boost::bind en combinaison avec std::for_each . Des choses plus sophistiquées sont possibles avec Boost.Lambda. Si vous êtes d'humeur à vous frustrer ou à frustrer vos collègues, je vous recommande les liants dépréciés suivants std::bind1st y std::bind2nd .

Voici un exemple de code :

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <boost/lambda/lambda.hpp>
#include <functional>    

int main()
{
  int i = 0;
  std::vector<int> v;
  std::generate_n(std::back_inserter(v), 10, [&]() {return i++;});

  // range-based for
  // keep it simple
  for(auto a : v)
    std::cout << a << " ";
  std::cout << std::endl;

  // lambda
  // i don't like loops
  std::for_each(v.begin(), v.end(), [](int x) { 
      std::cout << x << " ";
    });
  std::cout << std::endl;

  // hardcore
  // i know my lib
  std::copy(v.begin(), v.end(), std::ostream_iterator<int>(std::cout, " "));
  std::cout << std::endl;

  // boost lambda
  // this is what google came up with
  // using for the placeholder, otherwise this looks weird
  using namespace boost::lambda;
  std::for_each(v.begin(), v.end(), std::cout << _1 << " ");
  std::cout << std::endl;

  // fold
  // i want to be a haskell programmer
  std::accumulate(v.begin(), v.end(), std::ref(std::cout), 
                  [](std::ostream& o, int i) -> std::ostream& { return o << i << " "; });

  return 0;
}

62voto

jrok Points 30472

En C++11, si votre compilateur le supporte, oui, c'est possible. C'est ce que l'on appelle le "range-based for".

std::vector<int> v;

// fill vector

for (const int& i : v) { std::cout << i << "\n"; }

Cela fonctionne pour les tableaux de style C et pour tout type de tableau comportant des fonctions. begin() y end() qui renvoient des itérateurs. Exemple :

class test {
    int* array;
    size_t size;
public:
    test(size_t n) : array(new int[n]), size(n)
    {
        for (int i = 0; i < n; i++) { array[i] = i; }
    }
    ~test() { delete [] array; }
    int* begin() { return array; }
    int* end() { return array + size; }
};

int main()
{
    test T(10);
    for (auto& i : T) {
        std::cout << i;   // prints 0123456789
    }
}

13voto

Beginner Points 3096

Cette possibilité n'existe pas en C++03. Cependant, la nouvelle norme (C++11) l'offre. Voir l'exemple (tiré de Wikipedia ):

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

Pensez également à utiliser std::vector<int> au lieu d'un tableau ordinaire. Il s'agit d'une analogie du C++ pour les types de données du C, ce qui rend la vie plus facile.

12voto

arasmussen Points 5752

Oui et non.

1. Tableau local : Non, mais vous pouvez facilement trouver la taille

Si vous avez un tableau local ( int numbers[4] = {1, 2, 3, 4]; ), vous pouvez alors faire size = sizeof(numbers) / sizeof(int) .

2. Pointeur vers le tableau : Pas du tout, vous devez passer la taille séparément.

Si vous avez un pointeur sur un tableau ( int* numbers = new int[4]; ), vous ne pouvez pas déterminer la taille à moins d'en tenir compte vous-même. (ou si elle est à terminaison nulle dans le cas d'une chaîne c, mais alors vous devez itérer à travers elle ce qui est un temps de fonctionnement linéaire...)

Notez que je ne pense pas qu'un pointeur vers un tableau soit la terminologie appropriée. En fait, vous avez juste un pointeur vers le premier élément du tableau, mais l'espace pour plusieurs valeurs a été alloué. Je ne sais pas comment cela s'appelle. Peut-être juste un pointeur ?

3. Conteneurs STL : Oui, et vous pouvez faire un peu de magie de boucle for en utilisant des itérateurs, ou simplement utiliser des indices en obtenant la taille

Si vous avez un vecteur ( std::vector<int> v(3, 0); ), vous pouvez alors l'itérer de la manière suivante :

C++11 :

auto it = v.begin();
for (auto it = v.begin(); it != v.end(); it++)
{
    UseElement(*it);
}

Ou apparemment (également C++11, merci jrok) :

for (const int& i : v) { UseElement(i); }

C++ (pré-11) :

std::vector<int>::iterator it;
for (it = v.begin(); it != v.end(); it++)
{
    UseElement(*it);
}

Ou en utilisant des indices :

for (int i = 0; i < v.size(); i++)
{
    UseElement(v[i]);
}

En outre, vous pouvez utiliser des pointeurs de fonction ou des foncteurs avec des conteneurs STL à l'aide de la fonction for_each de std algorithm ( #include <algorithm> ) comme suit :

void foo(int i)
{
    std::cout << i;
}

{
    std::for_each(myvector.begin(), myvector.end(), foo);
}

6voto

Paul Manta Points 9409

Dans l'ancienne norme, C++03 (qui date de 2003), le langage n'a pas de support intégré pour ce type de for-loop. Il existe quelques artifices que vous pouvez utiliser avec Boost, mais je pense que cela ne vaut pas la peine d'inclure une toute nouvelle bibliothèque pour cette petite fonctionnalité pratique.

Dans la nouvelle norme, C++11 (qui a été publiée l'été dernier), c'est possible ; la syntaxe ressemble à ceci :

MyType array[] = { ... }
for (MyType& x : array) {
    ...
}

Notez que j'utilise MyType& x pas MyType x . En Java, tout est une référence. En C++, les références doivent être explicites, et vous les déclarez à l'aide de la commande & . Si vous n'utilisez pas de références, la boucle for copiera chaque élément du tableau dans le fichier x (ce qui pourrait être coûteux à faire).

Toutefois, C++11 n'est pas encore totalement pris en charge par la plupart des compilateurs. Je pense que Visual C++ de Microsoft prend en charge cette fonctionnalité, mais je n'en suis pas sûr.

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