È difficile avere un polimorfismo dinamico con gli iteratori in stile C++. operator++(int)
restituisce per valore, che afaik è intrattabile: non è possibile avere una funzione membro virtuale che restituisce *this
in base al valore senza essere affettato.
Se possibile, è consigliabile utilizzare i modelli come tutti gli altri dicono.
Tuttavia, se avete bisogno di polimorfismo dinamico, ad esempio perché non si può esporre l'attuazione di add_all_msgs come modello avrebbe fatto, allora io credo che si possa fingere di essere Java, in questo modo:
struct MessageIterator {
virtual Message &get() = 0;
virtual void next() = 0;
// add more functions if you need more than a Forward Iterator.
virtual ~MessageIterator() { }; // Not currently needed, but best be safe
};
// implementation elsewhere. Uses get() and next() instead of * and ++
void add_all_msgs(MessageIterator &it);
template <typename T>
struct Adaptor : public MessageIterator {
typename T::iterator wrapped;
Adaptor(typename T::iterator w) : wrapped(w) { }
virtual Message &get() {
return *wrapped;
}
virtual void next() {
++wrapped;
}
};
int main() {
std::deque<Message> v;
Adaptor<std::deque<Message> > a(v.begin());
add_all_msgs(a);
}
Ho controllato che questo compili, ma non l'ho ancora testato e non ho mai usato questo design prima. Inoltre non mi sono preoccupato della costanza: in pratica probabilmente vorrai un const Message &get() const
. E al momento l'adattatore non ha modo di sapere quando fermarsi, ma poi nemmeno il codice con cui hai iniziato, quindi ho ignorato anche questo. Fondamentalmente avresti bisogno di una funzione hasNext
che confronta wrapped
con un iteratore finale fornito al costruttore.
Potrebbe essere possibile eseguire un'operazione con una funzione di modello e riferimenti const, in modo che il client non debba conoscere o dichiarare quel tipo di adattatore sgradevole.
[Modifica: a pensarci bene, probabilmente è meglio disporre di un modello di funzione stub add_all_msgs
, che avvolge i suoi parametri in un adapter e quindi chiama real_add_all_msgs
. Questo nasconde completamente l'adattatore dal client.]
fonte
2009-07-09 15:27:43
La convenzione deve prendere gli iteratori in base al valore anziché al riferimento.A parte il fatto che gli iteratori sono normalmente "piccoli" in ogni caso, la ragione di questo (afaik) è di consentire al chiamante di passare un valore temporaneo, come un valore di ritorno da std :: back_inserter. C++ 0x aiuta in questo almeno in due modi a cui riesco a pensare. –
Heh, o il valore restituito da "begin" viene a pensarci. Il precedente codice "usage" non viene compilato: "inizializzazione non valida di riferimento non const di tipo" blah "da un carattere temporaneo di tipo" blah "". –
L'OP ha esplicitamente detto: "fino a quando l'iteratore sta iterando il messaggio". Questa soluzione, e la maggior parte delle altre, ha completamente ignorato questo requisito. –