Obecnie mogę wykonywać tylko pętle dystansowe za pomocą tego:
for (auto& value : values)
Ale czasami potrzebuję iteratora do wartości zamiast odniesienia (z dowolnego powodu). Czy jest jakaś metoda bez konieczności porównywania wartości przez cały wektor?
std::find
jeśli potrzebujesz zlokalizować wartość ... Stare dobre algorytmy są nadal w nowym standardzie.value
iit
może nie być zsynchronizowany. Pamiętajvalue
to odniesienie.++it
, abyit++
w miarę możliwości (zarówno zastosowań w kodzie), jak to może mieć mniejszy narzut.Oto klasa opakowująca proxy, która umożliwia ujawnienie ukrytego iteratora poprzez aliasowanie go do własnej zmiennej.
#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 ); }
Stosowanie:
#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'; }
źródło
Spróbowałem na tym i znalazłem rozwiązanie.
Stosowanie:
for(auto i : ForIterator(some_list)) { // i is the iterator, which was returned by some_list.begin() // might be useful for whatever reason }
Wdrożenie nie było takie trudne:
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); }
źródło
boost::counting_iterator
chociaż, który robi dokładnie to, i jest dogodnie owinięteboost::counting_range
, więc można napisać:for(auto it : boost::counting_range(r.begin(), r.end()))
. :)operator++()
powinienem zwrócićInnerIterator
, poza tym bardzo miły i nieprzyjemny.for
Pętla oparta na zakresie jest tworzona jako odpowiednik języka C ++ dla językaforeach
Java, co umożliwia łatwą iterację elementów tablicy. Jest przeznaczony do usuwania użycia złożonych struktur, takich jak iteratory, aby uprościć to. Jeśli chcesziterator
, jak powiedział Nawaz, będziesz musiał użyć normalnejfor
pętli.źródło
for
jest na cukrze składni i zmniejszeniu ilości wpisywanych znaków. Konieczność wyłuskiwania iteratora sprawi, że będzie on podatny na błędy, szczególnie w połączeniu zauto
Jest na to bardzo prosty sposób
std::vector
, który powinien również działać, jeśli zmieniasz rozmiar wektora w trakcie procesu (nie jestem pewien, czy zaakceptowana odpowiedź dotyczy tego przypadku)Jeśli
b
to twój wektor, możesz to zrobićfor(auto &i:b){ auto iter = b.begin() + (&i-&*(b.begin())); }
gdzie
iter
będzie wymagany iterator.Wykorzystuje to fakt, że wektory C ++ są zawsze ciągłe .
źródło
vector<T>::iterator
doT*
: Sprawdź to za pomocą astatic_assert()
, a następnie po prostu użyjT* iter = &i;
.Zróbmy to bardzo brudne ... Wiem, że 0x70h zmienia się wraz z użyciem stosu, wersją kompilatora ... Powinien być ujawniony przez kompilator, ale tak nie jest :-(
char* uRBP = 0; __asm { mov uRBP, rbp } Iterator** __pBegin = (Iterator**)(uRBP+0x70); for (auto& oEntry : *this) { if (oEntry == *pVal) return (*__pBegin)->iPos; }
źródło