Questo può essere fatto in C++11 usando modelli variadici. Continuando dalla risposta di Pete:
// Visitor template declaration
template<typename... Types>
class Visitor;
// specialization for single type
template<typename T>
class Visitor<T> {
public:
virtual void visit(T & visitable) = 0;
};
// specialization for multiple types
template<typename T, typename... Types>
class Visitor<T, Types...> : public Visitor<Types...> {
public:
// promote the function(s) from the base class
using Visitor<Types...>::visit;
virtual void visit(T & visitable) = 0;
};
template<typename... Types>
class Visitable {
public:
virtual void accept(Visitor<Types...>& visitor) = 0;
};
template<typename Derived, typename... Types>
class VisitableImpl : public Visitable<Types...> {
public:
virtual void accept(Visitor<Types...>& visitor) {
visitor.visit(static_cast<Derived&>(*this));
}
};
Sottoclassi di Visitable
:
class Mesh : public Object, public VisitableImpl<Mesh, Mesh, Text> {};
class Text : public Object, public VisitableImpl<Text, Mesh, Text> {};
Un Visitor
sottoclasse:
class Renderer : public Visitor<Mesh, Text> {};
Non è chiaro cosa sia il value_type
del tuo Scene
container è ma devi ottenere un riferimento o un puntatore a Visitable<Mesh, Text>
su cui chiamare accept
:
for(Scene::iterator it = scene.begin(); it != scene.end(); ++it) {
Visitable<Mesh, Text>& object = static_cast<Visitable<Mesh, Text>&>(*it);
if(pre_visit(object)) {
object.accept(*this);
post_visit(object);
}
}
Il tuo BaseVisitor non fa nulla per te, a parte consentire a visitatori arbitrari di eliminare il visitatore. Invece, vuoi avere una classe base per il visitatore che fornisce tutto dei diversi accept
funzioni che potrebbero essere richiamate su di esso e per il Visitable
per accettare questo visitatore.
Per fare ciò, puoi utilizzare un elenco di tipi per definire i tipi che il visitatore può accettare, avere una classe di base visitatorie che prende l'elenco di tipi e aggiungere l'elenco di tipi come parametro alla tua implementazione di visitatori.
schizzo di esempio:
// assuming a typelist has typedefs first and second and a
// type 'empty' representing end of type list
template<typename Types>
class Visitor : public Visitor<Types::second> {
public:
// visitor has a visit function for each type in Types
virtual void visit(typename Types::first& visitable) = 0;
};
template<> class Visitor<empty> { };
template<typename Types>
class Visitable{
public:
// base accepts a visitor which can visit any type in Types
virtual void accept(Visitor<Types>& visitor) = 0;
};
template<typename Derived, typename Types>
class VisitableImpl : public Visitable<Types> {
public:
// impl calls specific visit function
virtual void accept(Visitor<Types>& visitor) override {
visitor.visit(static_cast<Derived&>(*this));
}
};