Es difícil tener un polimorfismo dinámico con iteradores de estilo C++. operator++(int)
devuelve por valor, lo que afaik es intratable: no puede tener una función de miembro virtual que devuelve *this
por valor sin que se corte.
Si es posible, recomiendo usar plantillas como todo el mundo dice.
Sin embargo, si usted no necesita el polimorfismo dinámico, por ejemplo, porque no se puede exponer a la implementación de add_all_msgs como plantilla haría, entonces yo creo que se podría pretender ser Java, así:
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);
}
He comprobado que esto compila, pero no lo he probado y nunca he usado este diseño. Tampoco me he molestado con la estupidez. En la práctica, es probable que desee un const Message &get() const
. Y, por el momento, el adaptador no tiene forma de saber cuándo detenerse, pero tampoco el código con el que comenzó, así que ignoré eso también. Básicamente necesitaría una función hasNext
que compare wrapped
con un iterador final proporcionado al constructor.
Es posible que pueda hacer algo con una función de plantilla y const references, para que el cliente no tenga que saber o declarar ese desagradable tipo de adaptador.
[Editar: pensándolo bien, es probable que sea mejor tener una plantilla de función stub add_all_msgs
, que envuelve su parámetro en un adaptador y luego llama al real_add_all_msgs
. Esto oculta completamente el adaptador del cliente.]
La convención consiste en tomar iteradores por valor en lugar de por referencia.Aparte de que los iteradores son normalmente "pequeños" de todos modos, la razón para esto (afaik) es permitir que la persona que llama transmita un valor temporal, como un valor de retorno de std :: back_inserter. C++ 0x me ayuda con esto en al menos dos formas en las que puedo pensar. –
Heh, o el valor de retorno de "begin" empieza a pensarlo. El código de "uso" anterior no compila: "inicialización no válida de referencia no constante de tipo 'blah' de un temporal de tipo 'blah'". –
El OP dijo explícitamente: "siempre que el iterador repita el mensaje". Esta solución, y la mayoría de las demás, ignoraron por completo este requisito. –