2009-10-20 18 views
11

Ho una classe che voglio esporre un elenco di strutture (che contengono solo alcuni numeri interi). Non voglio l'esterno per modificare questi dati, basta scorrere su di esso e leggerli Esempio:Rendere la mia classe C++ iterabile tramite BOOST_FOREACH

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

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

ora nel mio codice che voglio usare la mia classe in questo modo:

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

Ho già letto questo articolo http://accu.org/index.php/journals/1527 sugli spazi membri. Tuttavia, non voglio (o non posso) salvare tutti i TestData in un vettore interno o qualcosa del genere. Questo perché la classe stessa non possiede la memoria, cioè non c'è in realtà un contenitore sottostante a cui sia possibile accedere direttamente dalla classe. La classe stessa può interrogare un componente esterno per ottenere l'elemento next, previous o ith, però.

Fondamentalmente voglio che la mia classe si comporti come se avesse una collezione, ma in realtà non ne ha uno. Qualche idea?

+4

non devi solo fornire funzioni di inizio/fine che restituiscono gli iteratori adatti? – jalf

+0

sì, ma non ho un contenitore sottostante che potrebbe fornirmi questi iteratori – newgre

+0

quindi scrivili tu stesso. :) La libreria Boost.Iterator dovrebbe essere subito operativa. – jalf

risposta

5

Sembra che si deve scrivere i propri iteratori.

La libreria Boost.Iterator dispone di numerosi modelli utili. Ho usato la loro classe base di Iterator Facade un paio di volte, ed è bello e facile definire i propri iteratori che lo utilizzano.

Ma anche senza di esso, gli iteratori non sono scienza missilistica. Devono solo esporre gli operatori giusti e i typedef. Nel tuo caso, saranno solo wrapper attorno alla funzione di query che devono chiamare quando vengono incrementati.

Una volta definita una classe di iteratore, è sufficiente aggiungere le funzioni membro begin() e end() alla classe.

Sembra che l'idea di base debba essere quella di chiamare la funzione di query quando l'iteratore viene incrementato, per ottenere il valore successivo. E la notifica dovrebbe quindi restituire il valore recuperato dall'ultima chiamata di query.

Può essere utile dare un'occhiata alla libreria standard stream_iterator s per alcune delle semantiche, dal momento che devono anche risolvere alcuni problemi "non abbiamo un contenitore e non possiamo creare iteratori che puntano in qualsiasi altro posto rispetto ai problemi di "posizione corrente".

Ad esempio, supponendo che sia necessario chiamare una funzione query() che restituisce NULL quando si raggiunge la fine della sequenza, la creazione di un "end-iterator" sarà complicata. In realtà, tutto ciò che serve è definire l'uguaglianza in modo che "gli iteratori siano uguali se entrambi memorizzano NULL come valore memorizzato nella cache". Quindi inizializzare l'iteratore di "fine" con NULL.

Può essere utile cercare la semantica richiesta per gli iteratori di input o se si sta leggendo la documentazione di Boost.Iterator, per gli iteratori a passaggio singolo in particolare. Probabilmente non sarai in grado di creare iteratori multipass. Quindi cerca esattamente quale comportamento è richiesto per un iteratore a passaggio singolo e atteniti a quello.

+0

E perché sono un bravo ragazzo: concetto di Input Iterator >> http://www.sgi.com/tech/stl/InputIterator.html –

0

Se il tipo di raccolta presenta un'interfaccia contenitore standard, non è necessario eseguire alcuna operazione per rendere BOOST_FOREACH funzionante con il tipo. In altre parole, se il tuo tipo ha iterator e const_iterator typedefs nidificati e begin() e end() funzioni membro, BOOST_FOREACH sa già come iterare sul tuo tipo. Non è richiesta alcuna ulteriore azione.

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

+0

Lo so, ma da dove otterrei quegli iteratori? Non esiste un contenitore sottostante i cui iteratori potrei usare – newgre

0

Dalla pagina di documentazione for_each Boost:

BOOST_FOREACH itera su sequenze. Ma cosa si qualifica come sequenza, esattamente? Poiché BOOST_FOREACH è costruito su Boost.Range, supporta automaticamente quei tipi che Boost.Range riconosce come sequenze. In particolare, BOOST_FOREACH funziona con tipi che soddisfano il concetto di intervallo a passaggio singolo. Ad esempio, possiamo utilizzare BOOST_FOREACH con:

Problemi correlati