slicing iterator
-
Hallo,
gibt es eine fertigen Iterator der nicht um 1 sondern um N weiter geht?
Danke + Gruß
-
Drehleiter schrieb:
gibt es eine fertigen Iterator der nicht um 1 sondern um N weiter geht?
Was hindert dich, statt "++it" einfach "std::advance(it,N)" zu schreiben? Für sowas brauchts keine extra Wrapper-Iteratoren.
-
pumuckl schrieb:
Drehleiter schrieb:
gibt es eine fertigen Iterator der nicht um 1 sondern um N weiter geht?
Was hindert dich, statt "++it" einfach "std::advance(it,N)" zu schreiben? Für sowas brauchts keine extra Wrapper-Iteratoren.
http://www.cplusplus.com/reference/std/iterator/advance/
If i is a Random Access Iterator, the function uses once operator+ or operator-, otherwise, the function uses repeatedly the increase or decrease operator (operator++ or operator--) until n elements have been advanced.
Wie wird denn differenziert, ob der Parameter ein Random Access Iterator ist oder nicht?
Also wie kann ich es Umsetzen, dass er wenn die Funktion x existiert, diese
aufgerufen wird und ansonsten Funktion y?
-
Unterschieden wird mit Hilfe von Iterator Tags Ein anderes Suchwort wäre TypeTraits.
-
Tobias Gerg schrieb:
Unterschieden wird mit Hilfe von Iterator Tags Ein anderes Suchwort wäre TypeTraits.
thx

-
Drehleiter schrieb:
gibt es eine fertigen Iterator der nicht um 1 sondern um N weiter geht?
nicht ganz, aber fast!
pumuckl schrieb:
Was hindert dich, statt "++it" einfach "std::advance(it,N)" zu schreiben?
Vielleicht die Tatsache, dass man mit Iteratoren i.A. Algorithmen aufruft, in denen stets nur einmal inkrementiert wird.
.. mit boost:
#include <iostream> #include <algorithm> // copy #include <vector> #include <iterator> // ostream_iterator, advance #include <boost/iterator/iterator_adaptor.hpp> template< typename T, int N > class Slicer : public boost::iterator_adaptor< Slicer< T, N >, T > { public: Slicer( T i = T() ) : iterator_adaptor_( i ) {} void increment() { std::advance( base_reference(), N ); // hier passiert das N x ++i } }; template< int N, typename T > // Factory-Funktion (reduziert die Schreibarbeit bei der Anwendung) Slicer< T, N > slice( T i ) { return Slicer< T, N >( i ); } int main() { using namespace std; const int arr[] = { 1, -2, 3, 4, -5, 6, -7, 8, 9, 10, -11, 12 }; vector< int > v( arr, arr+sizeof(arr)/sizeof(*arr) ); copy( slice<3>( v.begin() ), slice<3>( v.end() ), ostream_iterator< int >( cout << "> ", " " ) ); cout << endl; return 0; }Die Ausgabe bei dieser Demo wäre:
> 1 4 -7 10WARNUNG: bei dieser Konstruktion muss der Anwender garantieren, dass der Ende-Iterator auch erreicht wird. Also in diesem Fall ist die Größe des Vektors (=12) ein Vielfaches des Slice-Sprungs (=3).
Gruß
Werner
-
Die Sache hat leider einen kleinen Haken, nämlich, dass man bei einer naiven Implementierung typischerweise über das Ende der ursprünglichen Sequenz hinausspringt. Ich hatte mir auch einen solchen Iterator gebaut, mit dem ich über Elemente einer Matrixspalte iterieren kann, wobei die Elemente Zeilenweise in einem std::vector abgelegt waren. Der slice-Iterator speicherte nur einen Iterator und hat bei op++ eben +=N durchgeführt. Aber dabei kann es vorkommen, dass der Iterator nicht mehr gültig ist, weil er zuweit hinter das Ende der Sequenz zeigt
Beispiel bei einer 3x3-Matrix:
+---+---+---+ | 0 | 1 | 2 | +---+---+---+ | 3 | 4 | 5 | +---+---+---+ | 6 | 7 | 8 | +---+---+---+ |end| +---+Wenn ich hier ein Iterator-Paar für die 3. Spalte haben will, was soll dann der zweite speichern? end()+2 gibt es nicht. In diese Falle bin ich selbst getreten. Ich habe es erst gemerkt als ich den Debug-Modus der Standardbibliothek aktiviert hatte und ich dementsprechend Fehlermeldungen bzgl ungültiger Iteratoren gesehen habe.
Daher sollte man sich vielleicht auf Random-Access-Iteratoren beschränken, und die Elemente über gespeicherte Indizes adressieren...
... reference_type operator*() const { return m_base_iter[m_index]; } slice_iterator& operator++() { m_index += m_stride; return *this; } ...etc
-
In boost,range gibt es Adaptoren für sowas:
#include <boost/range/adaptor/strided.hpp> #include <boost/range/algorithm/copy.hpp> #include <vector> std::vector<int> v; //v fuellen boost::copy ( v | boost::adaptors::strided(2) // 2er Schrittweite , target );Es gibt auch noch alle möglichen anderen Adaptoren.
-
vieln Dank für alle Antworten und insbesondere für das Aufmerksam-Machen auf die Klippen. Ich werde es mal boost::range ausprobieren.
Gruß