web-dev-qa-db-fra.com

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'ai utilisées 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++?

54
jozefg

En C++ 11, si votre compilateur le prend en charge, oui. C'est ce qu'on appelle basé sur la plage pour.

std::vector<int> v;

// fill vector

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

Il fonctionne pour les tableaux de style C et tout type qui a des fonctions begin() et 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
    }
}
61
jrok

C++ 11 le fait. Ils sont appelés fors basés sur la plage. N'oubliez pas que vous devez qualifier le type en tant que référence ou référence à const.

La solution de contournement pour C++ 03 est BOOST_FOR_EACH ou boost :: bind en combinaison avec std :: for_each . Des choses plus fantaisistes sont possibles avec Boost.Lambda. Si vous êtes d'humeur à frustrer vous-même ou vos collègues, je recommande les classeurs obsolètes std::bind1st et 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;
}
73
pmr

Il n'y a pas une telle possibilité en C++ 03. Cependant, le nouveau standard (C++ 11) l'a. 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 C++ pour les types de données C, ce qui facilite la vie.

13
Beginner

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

Dans le nouveau standard, C++ 11 (qui a été publié l'été dernier), cela est possible; la syntaxe ressemble à ceci:

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

Notez que j'utilise MyType& x, ne 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 en utilisant &. Si vous n'utilisez pas de références, la boucle for copiera chaque élément du tableau dans x (ce qui pourrait être coûteux à faire).

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

6
Paul Manta

D'autres ont déjà mentionné que ce style de boucle avait été ajouté en C++ 11. Cependant, C++ 11 est encore meilleur:

for (auto const& item: numbers)
{
  std::cout << "Count is: " << item << '\n';
}

De cette façon, si vous changez plus tard le type d'élément de numbers de int à long, ou même à une classe bigint que vous avez écrite vous-même, vous ne ' t besoin de changer cela pour la boucle pas du tout.

6
celtschk

Je trouve cette macro simple très utile. La grande majorité de mes boucles for impliquent une itération sur un conteneur STL:

#define For(it, container) for( typeof((container).begin()) it = (container).begin(); it != (container).end(); ++it)

Un exemple:

vector<int> vector_of_ints;
... // initialize it somehow
For(integer, vector_of_ints) {
    cout << *integer << endl;
}

Il y a deux choses à prendre en compte avec ceci: Premièrement, c'est un itérateur et donc vous devez le déréférencer. Et deuxièmement, le deuxième paramètre du For sera évalué plusieurs fois. J'ai joué avec d'autres approches, mais je reviens toujours à la simplicité de cela.

3
Aaron McDaid