Je me suis retrouvé à écrire ceci il y a juste un peu:
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 que ce que j'ai écrit n'est peut-être pas le meilleur code. Et peut-être y a-t-il un moyen de le rendre plus flexible et utile. Mais il me semble que quelque chose comme ça aurait dû faire partie de la norme.
Donc est-il? Une sorte de nouvelle bibliothèque a-t-elle été ajoutée pour les itérateurs sur une plage d'entiers, ou peut-être une plage générique de valeurs scalaires calculées?
range
fonction de modèle? Cela n'ajoute rien à l'usage dans lequel ilrange_class
est utilisé. Je veux dire,range<0,10>()
et c'estrange_class<0,10>()
exactement la même chose!Réponses:
La bibliothèque standard C ++ n'en a pas, mais Boost.Range a boost :: counting_range , ce qui est certainement qualifié. Vous pouvez également utiliser boost :: irange , qui est un peu plus ciblé.
La bibliothèque de plages de C ++ 20 vous permettra de le faire via
view::iota(start, end)
.la source
std::experimental::ranges
espace de noms.range-v3
était toujours une sorte d'implémentation de référence, je dirais. Mais maintenant, je crois que les éléments de base de la gamme ont également été récemment adoptés en C ++ 20, nous allons donc les intégrerstd::
bientôt! :-)Autant que je sache, il n'existe pas de classe de ce type dans C ++ 11.
Quoi qu'il en soit, j'ai essayé d'améliorer votre implémentation. Je l'ai fait non-modèle , car je ne vois aucun avantage à en faire un modèle . Au contraire, il présente un inconvénient majeur: vous ne pouvez pas créer la plage au moment de l'exécution, car vous devez connaître les arguments du modèle au moment de la compilation.
Voici le code:
Code de test:
Production:
10 11 12 13 14 15 16 17 18 19
Démo Onine .
la source
iterator
àconst_iterator
, ontiterator
TIRENTstd::iterator
et ontrange
mettre en œuvrecbegin
etcend
. Oh et ... pourquoiiterator::operator++
renvoie une référence const ?[begin, end)
. @OP: +1 pour le jeu de mots sur les boucles basées sur une plage qui n'est pas un jeu de mots :-)v++
qui est censé renvoyer la valeur avant que l'opération d'incrémentation n'ait lieu. Je vous conseille d'explorer la différence entre++i
eti++
oùi
est déclaré êtreint
.J'ai écrit une bibliothèque appelée
range
exactement dans le même but, sauf qu'il s'agit d'une plage d'exécution, et l'idée dans mon cas est venue de Python. J'ai envisagé une version au moment de la compilation, mais à mon humble avis, il n'y a aucun avantage réel à obtenir la version au moment de la compilation. Vous pouvez trouver la bibliothèque sur bitbucket, et elle se trouve sous Boost License: Range . C'est une bibliothèque à un en-tête, compatible avec C ++ 03 et fonctionne comme un charme avec des boucles for basées sur une plage en C ++ 11 :)Caractéristiques :
Un véritable conteneur à accès aléatoire avec toutes les cloches et sifflets!
Les plages peuvent être comparées lexicographiquement.
Deux fonctions
exist
(retourne bool) etfind
(retourne l'itérateur) pour vérifier l'existence d'un nombre.La bibliothèque est testée à l'unité à l'aide de CATCH .
Exemples d'utilisation de base, utilisation de conteneurs standard, utilisation d'algorithmes standard et utilisation de boucles for basées sur une plage.
Voici une introduction d'une minute . Enfin, je me réjouis de toute suggestion concernant cette minuscule bibliothèque.
la source
J'ai trouvé que
boost::irange
c'était beaucoup plus lent que la boucle d'entiers canoniques. J'ai donc opté pour la solution beaucoup plus simple suivante en utilisant une macro de préprocesseur:Ensuite, vous pouvez faire une boucle comme ceci:
Cette plage démarre automatiquement à zéro. Il pourrait être facilement étendu pour commencer à partir d'un nombre donné.
la source
for (RANGE(i, flag? n1: n2))
cela donnera des résultats surprenants, car vous n'avez pas suivi l'une des règles de base des macros non-maléfiques, qui consiste à mettre entre parenthèses tous vos paramètres (y compris, dans ce cas,b
). Votre approche n'apporte pas non plus d'avantages en termes de performances par rapport à l'approche non macro, basée sur les "objets de plage" (par exemple, la réponse de Nawaz ).Voici un formulaire plus simple qui fonctionne bien pour moi. Y a-t-il des risques dans ma démarche?
r_iterator
est un type qui se comporte, autant que possible, comme unlong int
. Par conséquent, de nombreux opérateurs tels que==
et++
, passent simplement par lelong int
. J'expose le long int sous-jacent via les conversionsoperator long int
etoperator long int &
.( Edit: - nous pouvons rendre les méthodes
range
statiques au lieu de const.)la source
C'est peut-être un peu tard mais je viens de voir cette question et j'utilise cette classe depuis un moment maintenant:
Utilisation:
la source
as-tu essayé d'utiliser
La plupart du temps correspond à la facture.
Par exemple
Notez que printInt peut être remplacé par OFC par un lambda en C ++ 0x. Une autre petite variation de cette utilisation pourrait également être (strictement pour random_iterator)
Pour l'itérateur Fwd uniquement
la source
Vous pouvez facilement générer une séquence croissante en C ++ 11 en utilisant std :: iota ():
la source
range
classe doit modéliser la plage. Cependant, vous le construisez littéralement. C'est un gaspillage de mémoire et d'accès à la mémoire. La solution est très redondante, car le vecteur ne contient aucune information réelle à l'exception du nombre d'éléments et de la valeur du premier élément (s'il existe).