2011-09-26 10 views
57

Escribo un iterador para un contenedor que se usa en lugar de un contenedor STL. Actualmente, el contenedor STL se utiliza en muchos lugares con el c++11 foreach syntax, por ejemplo: for(auto &x: C). Hemos necesario para actualizar el código para utilizar una clase personalizada que envuelve el contenedor STL:C++ 11 sintaxis foreach e iterador personalizado

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

¿Cómo llego de automóviles para utilizar el iterador correcto para el contenedor personalizado por lo que el código es capaz de ser llamado en el siguiente ¿manera ?:

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

En general, ¿qué se necesita para garantizar que el auto utiliza el iterador correcto para una clase?

+0

Si está utilizando Visual Studio, puede colocar el cursor sobre el nombre de la variable para ver su tipo. IIRC, muestra el tipo real, no 'auto'. –

Respuesta

50

Usted tiene dos opciones:

funciones miembro
  • suministrados por el nombre begin y end que pueden ser llamados como C.begin() y C.end();
  • de otro modo, que asegure las funciones libres de nombre begin y end que se pueden encontrar usando las operaciones de búsqueda argumento dependiente, o en el espacio de nombres std, y puede ser llamado como begin(C) y end(C).
+2

Consulte las [Preguntas frecuentes sobre C++ 11 de Stroustrup] (http://www.stroustrup.com/C++11FAQ.html) para obtener una descripción detallada de la declaración ["Range-for"] (http: //www.stroustrup .com/C++ 11FAQ.html # para) (incluida la precedencia de miembro/función). – rluba

50

Para poder utilizar el rango para, su clase debe proporcionar const_iterator begin() const y const_iterator end() const miembros. También puede sobrecargar la función global begin, pero tener una función miembro es mejor en mi opinión. iterator begin() y const_iterator cbegin() const también se recomiendan, pero no son obligatorios. Si simplemente desea repetir un solo contenedor interno, que es muy fácil:

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

Si desea iterar sobre todo a medida, sin embargo, es probable que tiene que diseñar sus propios iteradores como clases dentro de su contenedor.

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

Para más detalles sobre cómo escribir una clase de iterador, ver my answer here.

2

Que yo sepa SomeSortedContainer solo necesita proporcionar begin() y end(). Y estos deberían devolver un iterador directo compatible con el estándar, en su caso SomeSortedContainerIterator, que en realidad incluiría un std::vector<Type>::iterator. Con el cumplimiento estándar me refiero a que debe proporcionar los operadores habituales de incremento y desreferenciación, pero también todos los value_type, reference_type, ... typedefs, que a su vez son utilizados por el constructo foreach para determinar el tipo subyacente de los elementos del contenedor. Pero puede enviarlos desde el std::vector<Type>::iterator.

+3

Si le faltan las funciones miembro 'begin' y' end', foreach también puede usar las funciones 'begin' y' end' non-member. –

+0

@Mike ¿Te refieres a funciones gratuitas que toman el contenedor como un parámetro único? Bien, no sabía eso. Útil para extender las clases de contenedores existentes, supongo. –

6

Como otros han dicho, el contenedor debe implementar begin() y end() funciones (o tienen funciones globales o std:: que se llevan a instancias de su contenedor como parámetros).

Esas funciones deben devolver el mismo tipo (generalmente container::iterator, pero eso es solo una convención). El tipo devuelto debe implementar operator*, operator++ y operator!=.