Existe-t-il un adaptateur de conteneur qui inverserait la direction des itérateurs afin que je puisse itérer sur un conteneur en sens inverse avec une boucle basée sur une plage?
Avec des itérateurs explicites, je convertirais ceci:
for (auto i = c.begin(); i != c.end(); ++i) { ...
en cela:
for (auto i = c.rbegin(); i != c.rend(); ++i) { ...
Je veux convertir ceci:
for (auto& i: c) { ...
pour ça:
for (auto& i: std::magic_reverse_adapter(c)) { ...
Existe-t-il une telle chose ou dois-je l'écrire moi-même?
c++
c++11
ranged-loops
Alex B
la source
la source
begin
àend
ou pour traiter les itérateurs de flux et similaires. Les algorithmes de plage seraient formidables, mais ils ne sont vraiment que du sucre syntaxique (à l'exception de la possibilité d'une évaluation paresseuse) sur les algorithmes d'itérateur.template<typename T> class reverse_adapter { public: reverse_adapter(T& c) : c(c) { } typename T::reverse_iterator begin() { return c.rbegin(); } typename T::reverse_iterator end() { return c.rend(); } private: T& c; };
Il peut être amélioré (ajout deconst
versions, etc.) mais cela fonctionne:vector<int> v {1, 2, 3}; reverse_adapter<decltype(v)> ra; for (auto& i : ra) cout << i;
impressions321
template<typename T> reverse_adapter<T> reverse_adapt_container(T &c) {return reverse_adapter<T>(c);}
Donc, vous pouvez simplement utiliserfor(auto &i: reverse_adapt_container(v)) cout << i;
pour itérer.parallel_for
servirait, avec une condition encore plus stricte «Je me fiche de l'ordre», si elle était incorporée dans la norme sous une forme ou une autre. Bien sûr, il pourrait aussi avoir un sucre syntaxique basé sur la plage :-)Réponses:
En fait , Boost avoir un tel adaptateur ne:
boost::adaptors::reverse
.la source
En fait, en C ++ 14, cela peut être fait avec très peu de lignes de code.
C'est une idée très similaire à la solution de @ Paul. En raison de choses manquantes dans C ++ 11, cette solution est un peu gonflée (plus la définition des odeurs std). Grâce à C ++ 14, nous pouvons le rendre beaucoup plus lisible.
L'observation clé est que les boucles for basées sur la plage fonctionnent en s'appuyant sur
begin()
etend()
pour acquérir les itérateurs de la plage. Grâce à ADL , on n'a même pas besoin de définir leur custombegin()
etend()
dans l'espace de noms std ::.Voici une solution d'échantillon très simple:
Cela fonctionne comme un charme, par exemple:
imprime comme prévu
NOTE
std::rbegin()
,std::rend()
etstd::make_reverse_iterator()
ne sont pas encore implémentés dans GCC-4.9. J'écris ces exemples selon la norme, mais ils ne compileraient pas en g ++ stable. Néanmoins, l'ajout de stubs temporaires pour ces trois fonctions est très simple. Voici un exemple d'implémentation, certainement pas complet mais qui fonctionne assez bien dans la plupart des cas:la source
forward<T>
dans votrereverse
implémentation.using namespace std
dans un en-tête, ce qui n'est pas une bonne idée. Ou est-ce que je manque quelque chose?Cela devrait fonctionner en C ++ 11 sans boost:
la source
std
espace de noms a un comportement indéfini selon 17.6.4.2.1.make_reverse_iterator
n'est pas dans l'std
espace de noms, donc il ne se heurtera pas à sa version C ++ 14.Est-ce que ça marche pour toi:
la source
par exemple:
la source
Si vous pouvez utiliser la gamme v3 , vous pouvez utiliser l'adaptateur de plage inverse
ranges::view::reverse
qui vous permet de visualiser le conteneur en sens inverse.Un exemple de travail minimal:
Voir DEMO 1 .
Remarque: Selon Eric Niebler , cette fonctionnalité sera disponible en C ++ 20 . Cela peut être utilisé avec l'en-
<experimental/ranges/range>
tête. Ensuite, lafor
déclaration ressemblera à ceci:Voir DEMO 2
la source
ranges::view
espace de noms a été renomméranges::views
. Alors, utilisezranges::views::reverse
.Si vous n'utilisez pas C ++ 14, je trouve ci-dessous la solution la plus simple.
Démo .
Cela ne fonctionne pas pour les conteneurs / types de données (comme le tableau), qui n'ont pas de
begin/rbegin, end/rend
fonctions.la source
Vous pouvez simplement utiliser
BOOST_REVERSE_FOREACH
ce qui se répète en arrière. Par exemple, le codegénère la sortie suivante:
la source