loop instead for examples based c++ iterator c++11

c++ - examples - use range based for loop instead



c++ 11 sintaxis foreach e iterador personalizado (4)

Como han indicado otros, su contenedor debe implementar las funciones begin() y end() (o tener funciones globales o std:: que toman 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!= .

Estoy escribiendo un iterador para un contenedor que se está utilizando en lugar de un contenedor STL. Actualmente, el contenedor STL se usa en muchos lugares con la sintaxis de c ++ 11 foreach, por ejemplo: for(auto &x: C) . Necesitamos actualizar el código para usar una clase personalizada que envuelva el contenedor STL:

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 hago que auto use el iterador correcto para el contenedor personalizado para que el código pueda ser llamado de la siguiente manera ?:

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

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


Para poder usar range-based for, su clase debe proporcionar const_iterator begin() const y const_iterator end() const members. También puede sobrecargar la función de begin global, pero tener una función de 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 iterar sobre un único contenedor interno, eso es REALMENTE 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();} };

Sin embargo, si desea iterar sobre algo personalizado, probablemente deba 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 obtener más detalles sobre cómo escribir una clase de iterador, consulte mi respuesta aquí .


Que yo sepa, SomeSortedContainer solo necesita proporcionar begin() y end() . Y estos deberían devolver un iterador avanzado compatible con el estándar, en su caso SomeSortedContainerIterator , que en realidad envolverí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 aquellos value_type , value_type reference_type , ... tipodef, que a su vez son utilizados por el constructo foreach para determinar el tipo subyacente de los elementos del contenedor. Pero puede enviarlos desde std::vector<Type>::iterator .


Tienes dos opciones:

  • usted proporciona funciones de miembro llamadas begin y end que se pueden llamar como C.begin() y C.end() ;
  • de lo contrario, usted proporciona funciones gratuitas llamadas begin y end que se pueden encontrar utilizando la búsqueda dependiente de argumentos, o en el espacio de nombres std , y se puede llamar como begin(C) y end(C) .