2011-09-26 14 views
57

Sto scrivendo un iteratore per un contenitore che viene utilizzato al posto di un container STL. Attualmente il container STL viene utilizzato in molti posti con c++11 foreach syntax ad es .: for(auto &x: C). Abbiamo bisogno di aggiornare il codice per utilizzare una classe personalizzata che avvolge il contenitore STL:C++ 11 foreach syntax e iteratore personalizzato

template< typename Type> 
class SomeSortedContainer{ 
    std::vector<typename Type> m_data; //we wish to iterate over this 
    //container implementation code 
};  
class SomeSortedContainerIterator{ 
    //iterator code 
}; 

Come faccio ad avere auto per utilizzare l'iteratore corretto per il contenitore personalizzato in modo che il codice è in grado di essere chiamato nel seguente modo ?:

SomeSortedContainer C; 
for(auto &x : C){ 
    //do something with x... 
} 

In generale, cosa è necessario per garantire che l'auto usi l'iteratore corretto per una classe?

+0

Se si utilizza Visual Studio, è possibile passare con il mouse sul nome della variabile per visualizzarne il tipo. IIRC, mostra il tipo effettivo, non 'auto'. –

risposta

50

Hai due scelte:

funzioni membro
  • forniti nome begin e end che possono essere chiamate come C.begin() e C.end();
  • in caso contrario, si forniscono le funzioni gratuite denominate begin e end che si possono trovare utilizzando la ricerca argomento-dipendente, o in namespace std, e può essere chiamato come begin(C) e end(C).
+2

Vedere le [Domande C++ 11] di Stroustrup (http://www.stroustrup.com/C++11FAQ.html) per una descrizione dettagliata dell'istruzione ["Intervallo-per"] (http: //www.stroustrup .com/C++ 11FAQ.html # for) (inclusa la precedenza membro/funzione). – rluba

50

Per poter utilizzare la gamma per, la classe deve fornire i membri const_iterator begin() const e const_iterator end() const. Puoi anche sovraccaricare la funzione globale begin, ma avere una funzione membro è migliore a mio avviso. iterator begin() e const_iterator cbegin() const sono anche raccomandati, ma non richiesti. Se si vuole semplicemente iterare su un unico contenitore interno, che è davvero facile:

template< typename Type> 
class SomeSortedContainer{ 

    std::vector<Type> m_data; //we wish to iterate over this 
    //container implementation code 
public: 
    typedef typename std::vector<Type>::iterator iterator; 
    typedef typename std::vector<Type>::const_iterator const_iterator; 

    iterator begin() {return m_data.begin();} 
    const_iterator begin() const {return m_data.begin();} 
    const_iterator cbegin() const {return m_data.cbegin();} 
    iterator end() {return m_data.end();} 
    const_iterator end() const {return m_data.end();} 
    const_iterator cend() const {return m_data.cend();} 
};  

Se si desidera iterare nulla su misura, però, probabilmente dovrete per progettare i propri iteratori come classi all'interno del contenitore.

class const_iterator : public std::iterator<random_access_iterator_tag, Type>{ 
    typename std::vector<Type>::iterator m_data; 
    const_iterator(typename std::vector<Type>::iterator data) :m_data(data) {} 
public: 
    const_iterator() :m_data() {} 
    const_iterator(const const_iterator& rhs) :m_data(rhs.m_data) {} 
    //const iterator implementation code 
}; 

Per maggiori dettagli sulla scrittura di una classe iteratore, vedi my answer here.

2

Per quanto ne so, il SomeSortedContainer deve fornire solo begin() e end(). E questi dovrebbero restituire un iteratore di inoltro compatibile standard, nel tuo caso SomeSortedContainerIterator, che in realtà avvolgerebbe uno std::vector<Type>::iterator. Con standard conformi intendo dire che deve fornire i soliti operatori di incremento e dereferenziazione, ma anche tutti quelli value_type, reference_type, ... typedefs, che a loro volta sono utilizzati dal costrutto foreach per determinare il tipo sottostante degli elementi del contenitore. Ma potresti semplicemente inoltrarli dallo std::vector<Type>::iterator.

+3

Se non si hanno le funzioni membro 'begin' e' end', allora foreach può anche usare le funzioni non membro 'begin' e 'end'. –

+0

@Mike Intendi le funzioni libere che prendono il contenitore come un singolo parametro? Bello, non lo sapevo. Utile per estendere le classi di contenitori esistenti, suppongo. –

6

Come altri hanno detto, il vostro contenitore deve implementare begin() e end() funzioni (o hanno funzioni globali o std:: che prendono le istanze del vostro contenitore come parametri).

Queste funzioni devono restituire lo stesso tipo (in genere container::iterator, ma questa è solo una convenzione). Il tipo restituito deve implementare operator*, operator++ e operator!=.