Creare i miei Iteratori


141

Sto cercando di imparare il C ++ quindi perdonami se questa domanda dimostra una mancanza di conoscenza di base, vedi, il fatto è che ho una mancanza di conoscenza di base.

Voglio un po 'di aiuto per capire come creare un iteratore per una classe che ho creato.

Ho una classe "Forma" che ha un contenitore di punti. Ho un 'pezzo' di classe che fa riferimento a una forma e definisce una posizione per la forma. Il pezzo non ha una forma ma fa solo riferimento a una forma.

Voglio che sembri che Piece sia un contenitore di punti identici a quelli della forma a cui fa riferimento ma con l'offset della posizione del pezzo aggiunto.

Voglio essere in grado di scorrere i punti del pezzo proprio come se il pezzo fosse un contenitore stesso. Ho letto un po 'in giro e non ho trovato nulla che mi abbia aiutato. Sarei molto grato per qualsiasi suggerimento.


6
La pubblicazione di un codice di esempio aiuterebbe a descrivere ciò che stai facendo meglio del semplice testo in inglese.
Greg Rogers,

3
La creazione di iteratori personalizzati non è probabilmente un top di base, almeno intermedio.
martedì

Risposte:


41

Dovresti usare Boost.Iterators. Contiene una serie di modelli e concetti per implementare nuovi iteratori e adattatori per iteratori esistenti. Ho scritto un articolo su questo argomento ; è sulla rivista ACCU del dicembre 2008. Discute un'elegante soluzione (IMO) per risolvere esattamente il tuo problema: esporre raccolte di membri da un oggetto, usando Boost.Iterators.

Se vuoi usare solo lo stl, il libro Josuttis ha un capitolo sull'implementazione dei tuoi iteratori STL.


3
Solo un'osservazione minore: il libro parla della C ++ Standard Library, non della STL - questi sono diversi, ma si confondono molto (anche io sono / ero colpevole)
CppChris

62

/ EDIT: vedo, qui è effettivamente necessario un proprio iteratore (ho prima letto male la domanda). Tuttavia, lascio che il codice qui sotto rimanga perché può essere utile in circostanze simili.


È davvero necessario un iteratore proprio qui? Forse è sufficiente inoltrare tutte le definizioni richieste al contenitore contenente i punti effettivi:

// Your class `Piece`
class Piece {
private:
    Shape m_shape;

public:

    typedef std::vector<Point>::iterator iterator;
    typedef std::vector<Point>::const_iterator const_iterator;

    iterator begin() { return m_shape.container.begin(); }

    const_iterator begin() const { return m_shape.container.begin(); }

    iterator end() { return m_shape.container.end(); }

    const_iterator end() const { return m_shape.const_container.end(); }
}

Questo presuppone che tu stia usando un vectorinternamente ma il tipo può essere facilmente adattato.


forse vuole usare l'algoritmo STL o le caratteristiche funzionali contro la sua classe ...
gbjbaanb

2
La domanda originale in realtà dice che l'iteratore del contenitore pezzi dovrebbe modificare i valori quando li restituisce. Ciò richiederebbe un iteratore separato, anche se probabilmente dovrebbe essere ereditato o altrimenti ottenuto principalmente dall'originale.
workmad3,

@gbjbaanb: Il bello del mio codice è che può essere utilizzato dagli algoritmi STL.
Konrad Rudolph,

1
Alcuni anni dopo e questo è ancora tra i migliori risultati su google ... Ora è possibile generalizzare questo facendo qualcosa del genere:auto begin() -> decltype(m_shape.container.begin()) { return m_shape.container.begin(); }
user2962533



2

Scrivere iteratori personalizzati in C ++ può essere abbastanza dettagliato e complesso da capire.

Dato che non riuscivo a trovare un modo minimo per scrivere un iteratore personalizzato, ho scritto questa intestazione del modello che potrebbe essere d'aiuto. Ad esempio, per rendere Pieceiterabile la classe:

#include <iostream>
#include <vector>

#include "iterator_tpl.h"

struct Point {
  int x;
  int y;
  Point() {}
  Point(int x, int y) : x(x), y(y) {}
  Point operator+(Point other) const {
    other.x += x;
    other.y += y;
    return other;
  }
};

struct Shape {
  std::vector<Point> vec;
};

struct Piece {
  Shape& shape;
  Point offset;
  Piece(Shape& shape, int x, int y) : shape(shape), offset(x,y) {}

  struct it_state {
    int pos;
    inline void next(const Piece* ref) { ++pos; }
    inline void begin(const Piece* ref) { pos = 0; }
    inline void end(const Piece* ref) { pos = ref->shape.vec.size(); }
    inline Point get(Piece* ref) { return ref->offset + ref->shape.vec[pos]; }
    inline bool cmp(const it_state& s) const { return pos != s.pos; }
  };
  SETUP_ITERATORS(Piece, Point, it_state);
};

Quindi sarai in grado di usarlo come un normale contenitore STL:

int main() {
  Shape shape;
  shape.vec.emplace_back(1,2);
  shape.vec.emplace_back(2,3);
  shape.vec.emplace_back(3,4);

  Piece piece(shape, 1, 1);

  for (Point p : piece) {
    std::cout << p.x << " " << p.y << std::endl;
    // Output:
    // 2 3
    // 3 4
    // 4 5
  }

  return 0;
}

Consente inoltre di aggiungere altri tipi di iteratori come const_iteratoro reverse_const_iterator.

Spero possa essere d'aiuto.


1

La soluzione al tuo problema non è la creazione dei tuoi stessi iteratori, ma l'uso di contenitori STL e iteratori esistenti. Conservare i punti in ogni forma in un contenitore come vettore.

class Shape {
    private:
    vector <Point> points;

Ciò che fai da allora in poi dipende dal tuo design. L'approccio migliore consiste nell'iterare i punti nei metodi all'interno di Shape.

for (vector <Point>::iterator i = points.begin(); i != points.end(); ++i)
    /* ... */

Se è necessario accedere a punti all'esterno di Shape (questo potrebbe essere un segno di un disegno carente) è possibile creare in metodi Shape che restituiranno le funzioni di accesso iteratore per i punti (in tal caso creare anche un typedef pubblico per il contenitore dei punti). Guarda la risposta di Konrad Rudolph per i dettagli di questo approccio.


3
Dovrà comunque creare il proprio iteratore che inoltra le richieste a Piece per le forme che si trovano in quel Piece. Gli iteratori personalizzati sono un ottimo strumento qui e molto eleganti da usare.
Roel,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.