2011-07-12 16 views
6

Aquí hay una encapsulación bastante normal de un contenedor STL que permite al usuario de Cfoo iterar el contenedor sin permitir cambios en las entrañas.iteración de contenedores STL encapsulados encapsulados

#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_; 
}; 

Hasta ahora, muy bien. Podemos repetir el contenedor de la siguiente manera:

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

Ahora quiero reemplazar el std :: vector con decir un std :: vector anidada:

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

private: 
    TbarVectorOuter barContainer_; 

Pero yo quiero ser capaz de recorrer en iteración todas las instancias de Cbar de la misma manera que antes, exponiendo un const_iterator, y un método const() de const y un const() de const().

No tengo claro cómo hacerlo, aunque sospecho que implica escribir un iterador personalizado. ¿Alguna idea?

+1

Implica escribir un iterador personalizado. –

+2

Suena como el trabajo para Flattening Iterator de http://stackoverflow.com/questions/3623082/flattening-iterator – Cubbi

+0

'TbarVector' debe ser privado, le dice al mundo exterior cosas que no son relevantes para él y es propenso al mal uso . –

Respuesta

4

Ninguno de los iteradores estándar puede iterar en más de un contenedor individual, por lo que su suposición es correcta: tendrá que escribir un iterador personalizado.

Es posible hacer esto de forma genérica, si tiene un iterador intermedio que devuelve pares de iteradores (de inicio, fin) a los contenedores internos.

Parte del código no probado para empezar:

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; 
}; 

Esto es sólo un comienzo, que puede volver a terminar - o no, dependiendo de this implementation ya cubre el mismo terreno.

+0

'operator ++()' falla 'return * this' – teivaz

+0

@teivaz gracias, corregido. –

Cuestiones relacionadas