Est-il possible d'itérer un vecteur de la fin au début?
for (vector<my_class>::iterator i = my_vector.end();
i != my_vector.begin(); /* ?! */ ) {
}
Ou est-ce seulement possible avec quelque chose comme ça:
for (int i = my_vector.size() - 1; i >= 0; --i) {
}
Eh bien, le meilleur moyen est:
for (vector<my_class>::reverse_iterator i = my_vector.rbegin();
i != my_vector.rend(); ++i ) {
}
rbegin ()/rend () spécialement conçu à cet effet. (Et oui, incrémenter un reverse_interator le fait reculer)
Maintenant, en théorie, votre méthode (en utilisant begin/end & --i
) fonctionnerait, l’itérateur de vector étant bidirectionnel, mais rappelez-vous, end () n’est pas le dernier élément - c’est un élément au-delà du dernier décrémentez d’abord, et vous avez terminé lorsque vous atteignez begin () - mais vous devez toujours effectuer votre traitement.
vector<my_class>::iterator i = my_vector.end();
while (i != my_vector.begin())
{
--i;
/*do stuff */ )
}
UPDATE: J'étais apparemment trop agressif en réécrivant la boucle for () dans une boucle while. (La partie importante est le --i
est au début.)
Si vous avez C++11
, vous pouvez utiliser auto
.
for (auto it = my_vector.rbegin(); it != my_vector.rend(); ++it)
{
}
Le "modèle" bien établi pour la répétition inverse dans les plages ouvertes-fermées se présente comme suit
// Iterate over [begin, end) range in reverse
for (iterator = end; iterator-- != begin; ) {
// Process `*iterator`
}
ou, si vous préférez,
// Iterate over [begin, end) range in reverse
for (iterator = end; iterator != begin; ) {
--iterator;
// Process `*iterator`
}
Ce modèle est utilisable, par exemple, pour l'indexation inversée d'un tableau à l'aide d'un index non signé
int array[N];
...
// Iterate over [0, N) range in reverse
for (unsigned i = N; i-- != 0; ) {
array[i]; // <- process it
}
(Les personnes qui ne connaissent pas ce modèle insistent souvent sur l’utilisation de types signed integer pour l’indexation de tableaux, précisément parce qu’elles croient à tort que les types non signés empêchent l’indexation inversée)
Il peut être utilisé pour itérer sur un tableau en utilisant une technique de "pointeur coulissant"
// Iterate over [array, array + N) range in reverse
for (int *p = array + N; p-- != array; ) {
*p; // <- process it
}
ou il peut être utilisé pour une itération inverse sur un vecteur en utilisant un itérateur ordinaire (et non inverse)
for (vector<my_class>::iterator i = my_vector.end(); i-- != my_vector.begin(); ) {
*i; // <- process it
}
Utilisateur rend() / rbegin()
itérateurs:
for (vector<myclass>::reverse_iterator it = myvector.rbegin(); it != myvector.rend(); it++)
template<class It>
std::reverse_iterator<It> reversed( It it ) {
return std::reverse_iterator<It>(std::forward<It>(it));
}
Ensuite:
for( auto rit = reversed(data.end()); rit != reversed(data.begin()); ++rit ) {
std::cout << *rit;
Alternativement, en C++ 14, faites simplement:
for( auto rit = std::rbegin(data); rit != std::rend(data); ++rit ) {
std::cout << *rit;
En C++ 03/11, la plupart des conteneurs standard ont également une méthode .rbegin()
et .rend()
.
Enfin, vous pouvez écrire l'adaptateur de plage backwards
comme suit:
namespace adl_aux {
using std::begin; using std::end;
template<class C>
decltype( begin( std::declval<C>() ) ) adl_begin( C&& c ) {
return begin(std::forward<C>(c));
}
template<class C>
decltype( end( std::declval<C>() ) ) adl_end( C&& c ) {
return end(std::forward<C>(c));
}
}
template<class It>
struct simple_range {
It b_, e_;
simple_range():b_(),e_(){}
It begin() const { return b_; }
It end() const { return e_; }
simple_range( It b, It e ):b_(b), e_(e) {}
template<class OtherRange>
simple_range( OtherRange&& o ):
simple_range(adl_aux::adl_begin(o), adl_aux::adl_end(o))
{}
// explicit defaults:
simple_range( simple_range const& o ) = default;
simple_range( simple_range && o ) = default;
simple_range& operator=( simple_range const& o ) = default;
simple_range& operator=( simple_range && o ) = default;
};
template<class C>
simple_range< decltype( reversed( adl_aux::adl_begin( std::declval<C&>() ) ) ) >
backwards( C&& c ) {
return { reversed( adl_aux::adl_end(c) ), reversed( adl_aux::adl_begin(c) ) };
}
et maintenant vous pouvez faire ceci:
for (auto&& x : backwards(ctnr))
std::cout << x;
ce que je pense est assez jolie.
Utilisez les itérateurs inversés et passez de rbegin()
à rend()
J'aime l'itérateur à la fin de Yakk - la réponse d'Adam Nevraumont, mais cela semblait compliqué pour ce dont j'avais besoin, alors j'ai écrit ceci:
template <class T>
class backwards {
T& _obj;
public:
backwards(T &obj) : _obj(obj) {}
auto begin() {return _obj.rbegin();}
auto end() {return _obj.rend();}
};
Je suis capable de prendre un itérateur normal comme ceci:
for (auto &elem : vec) {
// ... my useful code
}
et changez cela en itérer en sens inverse:
for (auto &elem : backwards(vec)) {
// ... my useful code
}
Voici une implémentation super simple qui permet d'utiliser la construction for each et qui ne s'appuie que sur la bibliothèque std C++ 14:
namespace Details {
// simple storage of a begin and end iterator
template<class T>
struct iterator_range
{
T beginning, ending;
iterator_range(T beginning, T ending) : beginning(beginning), ending(ending) {}
T begin() const { return beginning; }
T end() const { return ending; }
};
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// usage:
// for (auto e : backwards(collection))
template<class T>
auto backwards(T & collection)
{
using namespace std;
return Details::iterator_range(rbegin(collection), rend(collection));
}
Cela fonctionne avec des choses qui fournissent un rbegin () et un rend (), ainsi qu'avec des tableaux statiques.
std::vector<int> collection{ 5, 9, 15, 22 };
for (auto e : backwards(collection))
;
long values[] = { 3, 6, 9, 12 };
for (auto e : backwards(values))
;