resueltos - Implementando el patrón de visitante usando plantillas de C++
get y set c++ ejemplos (2)
Esto se puede hacer en C ++ 11 usando plantillas variadic. Continuando con la respuesta de 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));
}
};
Subclases de Visitable
:
class Mesh : public Object, public VisitableImpl<Mesh, Mesh, Text> {};
class Text : public Object, public VisitableImpl<Text, Mesh, Text> {};
Una subclase de Visitor
:
class Renderer : public Visitor<Mesh, Text> {};
No está claro cuál es el value_type
de su contenedor de Scene
, pero necesita obtener una referencia o un puntero a Visitable<Mesh, Text>
al que llamar 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);
}
}
He estado tratando de reducir la cantidad de repetición en mi código, mediante el uso de plantillas de C ++ para implementar el patrón de visitante. Hasta ahora he llegado a esto:
class BaseVisitor {
public:
virtual ~BaseVisitor() {}
};
template<typename T>
class Visitor : public BaseVisitor {
public:
virtual void visit(T& /* visitable */) = 0;
};
template<typename Derived>
class Visitable {
public:
void accept(Visitor<Derived>& visitor) {
visitor.visit(static_cast<Derived&>(*this));
}
};
Y cada subclase de Visitable se ve así:
class Mesh : public Object, public Visitable<Mesh> {};
class Text : public Object, public Visitable<Text> {};
Y finalmente el Visitante se ve así:
class Renderer : public Visitor<Mesh>, public Visitor<Text> {}
Hasta aquí todo bien ... ahora este es el problema:
for(Scene::iterator it = scene.begin(); it != scene.end(); ++it) {
Object& object = static_cast<Object&>(*it);
if(pre_visit(object)) {
object.accept(this); ///Erm, what do I cast to??
post_visit(object);
}
}
De alguna forma, tengo que enviar a Visitable para que pueda llamar a accept (), pero obviamente no sé qué es T. Alternativamente, no puedo agregar un accept virtual () a la plantilla Visitable, porque no sé qué argumento debería tomar.
Cualquier gurú de las plantillas de C ++ sabe cómo hacer que esto funcione?
Su BaseVisitor no hace nada por usted, más que permitir que los visitantes arbitrarios eliminen al visitante. En su lugar, desea tener una clase base para el visitante que proporcione todas las diferentes funciones de accept
que se puedan invocar en ella, y para que Visitable
acepte a este visitante.
Para hacer esto, puede usar una lista de tipos para definir los tipos que el visitante puede aceptar, tener una clase de visita base que tome la lista de tipos y agregar la lista de tipos como un parámetro a su implementación de visitae.
esbozo de ejemplo:
// 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));
}
};