2011-07-12 2 views
6

Voici une encapsulation assez normale d'un conteneur STL qui permet à l'utilisateur de Cfoo d'itérer le conteneur sans permettre de modifier les entrailles.itération de conteneurs STL imbriqués encapsulés

#include <vector> 

class Cfoo 
{ 
public: 
    class Cbar 
    { 
     /* contents of Cbar */ 
    }; 
    typedef std::vector<Cbar> TbarVector; 
    typedef TbarVector::const_iterator const_iterator;  
public: 
    const_iterator begin() const { return(barVector_.begin()); } 
    const_iterator end() const { return(barVector_.end()); } 
private: 
    TbarVector barVector_; 
}; 

Jusqu'ici, tout va bien. On peut itérer le récipient comme celui-ci:

Cfoo myFoo; 
for (Cfoo::const_iterator it = myFoo.begin(); it != myFoo.end(); ++it) 
{ 
    it->DoSomething(); 
} 

Maintenant, je veux remplacer le std :: vecteur dire un std :: vecteur imbriqué:

public: 
    typedef std::vector<Cbar> TbarVectorInner; 
    typedef std::vector<TbarVectorInner> TbarVectorOuter; 

private: 
    TbarVectorOuter barContainer_; 

Mais je veux être en mesure de parcourir toutes les instances de Cbar de la même manière qu'avant, exposant un const_iterator, et une méthode const() const et const (end const).

Je ne sais pas comment faire cela, même si je suppose que cela implique l'écriture d'un itérateur personnalisé. Des pensées?

+1

Il s'agit d'écrire un itérateur personnalisé. –

+2

On dirait que le travail pour Flattening Iterator de http://stackoverflow.com/questions/3623082/flattening-iterator – Cubbi

+0

'TbarVector' devrait être privé, il dit au monde extérieur des choses qui ne sont pas pertinentes et qui sont sujettes à une mauvaise utilisation . –

Répondre

4

Aucun des itérateurs standard ne peut parcourir plus d'un conteneur. Votre hypothèse est donc correcte: vous devez écrire un itérateur personnalisé.

Il est possible de le faire de manière générique, si vous avez un itérateur intermédiaire qui retourne des paires d'itérateurs (début, fin) aux conteneurs internes.

Certains code non testé pour commencer:

template<typename T, typename OuterIterator, typename InnerIterator> 
class Iterator2d : std::Iterator 
{ 
public: 
    Iterator2d(OuterIterator begin, OuterIterator end) : m_begin(begin), m_end(end), m_currentOuter(begin) { 
     if (m_currentOuter != m_end) 
      m_currentInner = m_begin->first; 
     Normalize(); 
    } 
    Iterator2d & operator++() 
    { 
     if (m_currentOuter != m_end) 
     { 
      ++m_currentInner; 
      Normalize(); 
     } 
     return *this; 
    } 
    T & operator*() 
    { 
     return *m_currentInner; 
    } 
private: 
    void Normalize() 
    { 
     while (m_currentOuter != m_end && m_currentInner == m_currentOuter->second) 
     { 
      ++m_currentOuter; 
      if (m_currentOuter != m_end) 
       m_currentInner = m_currentOuter->first; 
     } 
    } 

    OuterIterator m_begin; 
    OuterIterator m_end; 
    OuterIterator m_currentOuter; 
    InnerIterator m_currentInner; 
}; 

Ceci est juste un début, je peux revenir pour terminer - ou non, selon this implementation couvre déjà le même terrain.

+0

'opérateur ++()' manque 'retour * this' – teivaz

+0

@teivaz merci, corrigé. –

Questions connexes