Actuellement, je ne peux faire que des boucles basées à distance avec ceci:
for (auto& value : values)
Mais parfois, j'ai besoin d'un itérateur de la valeur, au lieu d'une référence (pour une raison quelconque). Existe-t-il une méthode sans avoir à parcourir tout le vecteur de comparaison des valeurs?
std::find
si ce dont vous avez besoin est de localiser une valeur ... Les bons vieux algorithmes sont toujours dans le nouveau standard.value
etit
peut ne pas être synchronisé. Remembervalue
est une référence.++it
àit++
chaque fois que possible ( les deux utilisations dans votre code) car il pourrait avoir une moindre frais généraux.Voici une classe de wrapper proxy pour vous permettre d'exposer l'itérateur caché en l'aliasant sur votre propre variable.
#include <memory> #include <iterator> /* Only provides the bare minimum to support range-based for loops. Since the internal iterator of a range-based for is inaccessible, there is no point in more functionality here. */ template< typename iter > struct range_iterator_reference_wrapper : std::reference_wrapper< iter > { iter &operator++() { return ++ this->get(); } decltype( * std::declval< iter >() ) operator*() { return * this->get(); } range_iterator_reference_wrapper( iter &in ) : std::reference_wrapper< iter >( in ) {} friend bool operator!= ( range_iterator_reference_wrapper const &l, range_iterator_reference_wrapper const &r ) { return l.get() != r.get(); } }; namespace unpolluted { /* Cannot call unqualified free functions begin() and end() from within a class with members begin() and end() without this hack. */ template< typename u > auto b( u &c ) -> decltype( begin( c ) ) { return begin( c ); } template< typename u > auto e( u &c ) -> decltype( end( c ) ) { return end( c ); } } template< typename iter > struct range_proxy { range_proxy( iter &in_first, iter in_last ) : first( in_first ), last( in_last ) {} template< typename T > range_proxy( iter &out_first, T &in_container ) : first( out_first ), last( unpolluted::e( in_container ) ) { out_first = unpolluted::b( in_container ); } range_iterator_reference_wrapper< iter > begin() const { return first; } range_iterator_reference_wrapper< iter > end() { return last; } iter &first; iter last; }; template< typename iter > range_proxy< iter > visible_range( iter &in_first, iter in_last ) { return range_proxy< iter >( in_first, in_last ); } template< typename iter, typename container > range_proxy< iter > visible_range( iter &first, container &in_container ) { return range_proxy< iter >( first, in_container ); }
Usage:
#include <vector> #include <iostream> std::vector< int > values{ 1, 3, 9 }; int main() { // Either provide one iterator to see it through the whole container... std::vector< int >::iterator i; for ( auto &value : visible_range( i, values ) ) std::cout << "# " << i - values.begin() << " = " << ++ value << '\n'; // ... or two iterators to see the first incremented up to the second. auto j = values.begin(), end = values.end(); for ( auto &value : visible_range( j, end ) ) std::cout << "# " << j - values.begin() << " = " << ++ value << '\n'; }
la source
Je me suis essayé et j'ai trouvé une solution.
Usage:
for(auto i : ForIterator(some_list)) { // i is the iterator, which was returned by some_list.begin() // might be useful for whatever reason }
La mise en œuvre n'a pas été si difficile:
template <typename T> struct Iterator { T& list; typedef decltype(list.begin()) I; struct InnerIterator { I i; InnerIterator(I i) : i(i) {} I operator * () { return i; } I operator ++ () { return ++i; } bool operator != (const InnerIterator& o) { return i != o.i; } }; Iterator(T& list) : list(list) {} InnerIterator begin() { return InnerIterator(list.begin()); } InnerIterator end() { return InnerIterator(list.end()); } }; template <typename T> Iterator<T> ForIterator(T& list) { return Iterator<T>(list); }
la source
boost::counting_iterator
bien, ce qui fait exactement cela, et est idéalement enveloppé avecboost::counting_range
, de sorte que vous pouvez écrire:for(auto it : boost::counting_range(r.begin(), r.end()))
. :)operator++()
faudrait retourner unInnerIterator
, sinon très agréable et utile.La
for
boucle basée sur la plage est créée en tant que contrepartie c ++ pourforeach
en java qui permet une itération facile des éléments du tableau. Il est destiné à supprimer l'utilisation de structures complexes comme les itérateurs afin de le rendre simple. Si vous voulez uniterator
, comme Nawaz l'a dit, vous devrez utiliser unefor
boucle normale .la source
for
est basée sur le sucre de syntaxe et la réduction de la quantité de frappe. Le fait de devoir déréférencer l'itérateur le rendrait sujet aux erreurs, en particulier lorsqu'il est utilisé avecauto
Il existe un moyen très simple de le faire pour
std::vector
, qui devrait également fonctionner si vous redimensionnez le vecteur pendant le processus (je ne suis pas sûr que la réponse acceptée considère ce cas)Si
b
c'est votre vecteur, vous pouvez simplement fairefor(auto &i:b){ auto iter = b.begin() + (&i-&*(b.begin())); }
où
iter
sera votre itérateur requis.Cela tire parti du fait que les vecteurs C ++ sont toujours contigus .
la source
vector<T>::iterator
àT*
: Vérifiez cela avec astatic_assert()
, puis utilisez simplementT* iter = &i;
.Faisons-le très sale ... Je sais, le 0x70h change avec l'utilisation de la pile, la version du compilateur, .... Il devrait être exposé par le compilateur, mais ce n'est pas :-(
char* uRBP = 0; __asm { mov uRBP, rbp } Iterator** __pBegin = (Iterator**)(uRBP+0x70); for (auto& oEntry : *this) { if (oEntry == *pVal) return (*__pBegin)->iPos; }
la source