2009-10-20 15 views
11

Tengo una clase que quiero exponer una lista de estructuras (que solo contiene algunos enteros). no quiero el exterior de modificar estos datos, simplemente iterar sobre ella y les lee Ejemplo:Hacer iterable mi clase de C++ a través de BOOST_FOREACH

struct TestData 
{ 
    int x; 
    int y; 
    // other data as well 
} 

class IterableTest 
{ 
    public: 
    // expose TestData here 
}; 

ahora en mi código Quiero usar mi clase como esta:

IterableTest test; 
BOOST_FOREACH(const TestData& data, test.data()) 
{ 
    // do something with data 
} 

Ya leí este artículo http://accu.org/index.php/journals/1527 sobre los espacios de miembros. Sin embargo, no quiero (ni puedo) guardar todos TestData en un vector interno o algo así. Esto se debe a que la clase en sí misma no posee el almacenamiento, es decir, no hay ningún contenedor subyacente al que la clase pueda acceder directamente. Sin embargo, la clase en sí misma puede consultar un componente externo para obtener el elemento siguiente, anterior o ith.

Así que, básicamente, quiero que mi clase se comporte como si tuviera una colección, pero de hecho no tiene una. Alguna idea?

+4

¿no solo tiene que proporcionar funciones de inicio/final devolviendo iteradores adecuados? – jalf

+0

sí, pero no tengo un contenedor subyacente que pueda proporcionarme estos iteradores – newgre

+0

, así que escríbelos usted mismo. :) La biblioteca Boost.Iterator debería ponerlo en funcionamiento con bastante rapidez. – jalf

Respuesta

5

Parece que usted tiene que escribir sus propios iteradores.

La biblioteca Boost.Iterator tiene varias plantillas útiles. He usado su clase base Iterator Facade un par de veces, y es agradable y fácil definir tus propios iteradores que la usan.

Pero incluso sin él, los iteradores no son ciencia de cohetes. Simplemente tienen que exponer a los operadores correctos y typedefs. En su caso, solo serán envoltorios de la función de consulta a la que tienen que llamar cuando se incrementen.

Una vez que haya definido una clase de iterador, solo tiene que agregar begin() y end() funciones de miembro a su clase.

Parece que la idea básica será llamar a la función de consulta cuando el iterador se incrementa para obtener el siguiente valor. Y la desreferencia debe devolver el valor recuperado de la última llamada de consulta.

Puede ser útil echar un vistazo a la biblioteca estándar stream_iterator s para algunas de las semánticas, ya que también tienen que trabajar con algunos sospechosos "realmente no tenemos un contenedor y no podemos crear iteradores apuntando en cualquier lugar que no sea en la posición actual de la corriente "problemas.

Por ejemplo, suponiendo que necesita llamar a una función query() que devuelve NULL cuando ha llegado al final de la secuencia, crear un "iterador final" va a ser complicado. Pero realmente, todo lo que necesita es definir la igualdad para que "los iteradores sean iguales si ambos almacenan NULL como su valor en caché". Entonces inicialice el iterador "final" con NULL.

Puede ser útil buscar la semántica requerida para los iteradores de entrada, o si está leyendo la documentación de Boost.Iterator, específicamente para los iteradores de un solo paso. Probablemente no podrá crear iteradores multipasadas. Así que busque exactamente qué comportamiento se requiere para un iterador de un solo paso y apéguese a eso.

+0

Y porque soy un chico agradable: Input Iterator concept >> http://www.sgi.com/tech/stl/InputIterator.html –

0

Si su tipo de colección presenta una interfaz de contenedor estándar, no necesita hacer nada para que BOOST_FOREACH funcione con su tipo. En otras palabras, si su tipo tiene iterator y const_iterator typedefs anidados, y begin() y end() funciones miembro, BOOST_FOREACH ya sabe cómo iterar sobre su tipo. No se requiere ninguna acción adicional.

http://boost-sandbox.sourceforge.net/libs/foreach/doc/html/boost_foreach/extending_boost_foreach.html

+0

Lo sé, pero ¿de dónde obtendré esos iteradores? No hay un contenedor subyacente cuyos iteradores pueda usar – newgre

0

Desde la página de documentación for_each Boost:

itera BOOST_FOREACH más secuencias. Pero, ¿qué califica como una secuencia, exactamente? Como BOOST_FOREACH está construido sobre Boost.Range, admite automáticamente aquellos tipos que Boost.Range reconoce como secuencias. Específicamente, BOOST_FOREACH funciona con tipos que satisfacen el concepto de rango de pase único. Por ejemplo, podemos usar BOOST_FOREACH con:

Cuestiones relacionadas