112 votes

Existe-t-il une classe d'intervalle dans C ++ 11 à utiliser avec les boucles for basées sur range?

Je me suis retrouvé à écrire cela juste un peu plus tôt:

template <long int T_begin, long int T_end>
class range_class {
 public:
   class iterator {
      friend class range_class;
    public:
      long int operator *() const { return i_; }
      const iterator &operator ++() { ++i_; return *this; }
      iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }

      bool operator ==(const iterator &other) const { return i_ == other.i_; }
      bool operator !=(const iterator &other) const { return i_ != other.i_; }

    protected:
      iterator(long int start) : i_ (start) { }

    private:
      unsigned long i_;
   };

   iterator begin() const { return iterator(T_begin); }
   iterator end() const { return iterator(T_end); }
};

template <long int T_begin, long int T_end>
const range_class<T_begin, T_end>
range()
{
   return range_class<T_begin, T_end>();
}

Et cela me permet d'écrire des choses comme ceci:

for (auto i: range<0, 10>()) {
    // stuff with i
}

Maintenant, je sais ce que j'ai écrit est peut-être pas le meilleur code. Et peut-être il ya un moyen de le rendre plus souple et plus utile. Mais il me semble que quelque chose comme cela aurait dû être fait partie de la norme.

Ainsi en est-il? Était une sorte de nouvelle bibliothèque ajoutée pour les itérateurs sur une plage de nombres entiers, ou peut-être une offre générique de calculé les valeurs scalaires?

69voto

Nicol Bolas Points 133791

La bibliothèque standard C ++ n'en a pas, mais Boost.Range a boost :: counting_range , ce qui le qualifie certainement. Vous pouvez également utiliser boost :: irange , qui est un peu plus ciblé.

51voto

Nawaz Points 148870

Autant que je sache, il n'existe pas de classe en C++11.

De toute façon, j'ai essayé d'améliorer votre mise en œuvre. J'ai fait de la non-modèle, car je ne vois aucun avantage à en faire le modèle. Au contraire, il a un inconvénient majeur : que vous ne pouvez pas créer la gamme au moment de l'exécution, vous avez besoin de connaître les arguments de modèle au moment de la compilation elle-même.

//your version
auto x = range<m,n>(); //m and n must be known at compile time

//my version
auto x = range(m,n);  //m and n may be known at runtime as well!

Voici le code:

class range {
 public:
   class iterator {
      friend class range;
    public:
      long int operator *() const { return i_; }
      const iterator &operator ++() { ++i_; return *this; }
      iterator operator ++(int) { iterator copy(*this); ++i_; return copy; }

      bool operator ==(const iterator &other) const { return i_ == other.i_; }
      bool operator !=(const iterator &other) const { return i_ != other.i_; }

    protected:
      iterator(long int start) : i_ (start) { }

    private:
      unsigned long i_;
   };

   iterator begin() const { return begin_; }
   iterator end() const { return end_; }
   range(long int  begin, long int end) : begin_(begin), end_(end) {}
private:
   iterator begin_;
   iterator end_;
};

Le code de Test:

int main() {
      int m, n;
      std::istringstream in("10 20");
      if ( in >> m >> n ) //using in, because std::cin cannot be used at coliru.
      {
        if ( m > n ) std::swap(m,n); 
        for (auto i : range(m,n)) 
        {
             std::cout << i << " ";
        }
      }
      else 
        std::cout <<"invalid input";
}

Sortie:

10 11 12 13 14 15 16 17 18 19

Onine démo.

13voto

AraK Points 38702

J'ai écrit une bibliothèque appelée range pour exactement le même effet sauf que c'est un moment de l'exécution de gamme, et de l'idée dans mon cas, est venu à partir de Python. J'ai envisagé un moment de la compilation de la version, mais à mon humble avis il n'y a pas de réel avantage pour gagner la compilation de la version. Vous pouvez trouver à la bibliothèque sur bitbucket, et il est sous Licence Boost: Gamme. C'est un en-tête de la bibliothèque, compatible avec le C++03 et fonctionne comme un charme avec une gamme à base de boucles en C++11 :)

Caractéristiques:

  • Un vrai accès aléatoire conteneur avec tous les cloches et de sifflets!

  • Les plages peuvent être comparées de manière lexicographique.

  • Deux fonctions exist(retourne bool), et find(retourne un itérateur) pour vérifier l'existence d'un nombre.

  • La bibliothèque est l'unité testée à l'aide de CAPTURE.

  • Des exemples de base l'utilisation, en travaillant avec des conteneurs standard, en travaillant avec la norme algorithmes et de travail avec la gamme de base pour les boucles.

Voici une introduction minute. Enfin, je souhaite la bienvenue à toute suggestion au sujet de cette petite bibliothèque.

2voto

Aaron McDaid Points 7761

Ici est une forme plus simple qui fonctionne bien pour moi. Quels sont les risques dans ma démarche?

r_iterator est un type qui se comporte, autant que possible, comme un long int. Par conséquent, de nombreux opérateurs comme == et ++, il suffit de passer à l' long int. J' "exposer" le sous-jacent long int via l' operator long int et operator long int & des conversions.

#include <iostream>
using namespace std;

struct r_iterator {
        long int value;
        r_iterator(long int _v) : value(_v) {}
        operator long int () const { return value; }
        operator long int& ()      { return value; }
        long int operator* () const { return value; }
};
template <long int _begin, long int _end>
struct range {
        static r_iterator begin() {return _begin;}
        static r_iterator end  () {return _end;}
};
int main() {
        for(auto i: range<0,10>()) { cout << i << endl; }
        return 0;
}

(Edit: - nous pouvons rendre les méthodes d' range statique au lieu de const.)

-1voto

Ajeet Points 1642

avez-vous essayé d'utiliser

 template <class InputIterator, class Function>
   Function for_each (InputIterator first, InputIterator last, Function f);
 

La plupart du temps correspond à la facture.

Par exemple

 template<class T> void printInt(T i) {cout<<i<<endl;}
void test()
{
 int arr[] = {1,5,7};
 vector v(arr,arr+3);

 for_each(v.begin(),v.end(),printInt);

}
 

Notez que printInt peut OFC être remplacé par un lambda dans C ++ 0x. De plus, une autre petite variation de cet usage pourrait être (strictement pour random_iterator)

  for_each(v.begin()+5,v.begin()+10,printInt);
 

Pour Fwd seulement itérateur

  for_each(advance(v.begin(),5),advance(v.begin(),10),printInt);
 

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