I\'ve been trying to reduce the amount of boilerplate in my code, by using C++ Templates to implement the visitor pattern. So far I\'ve come up with this:
cl
I was also in need of a templated Visitor pattern, and was able to create a solution that does not involve the usage of variadic types or type lists.
// forward declarations for our Visitable interface
class Object;
class Visitor;
// Visitable objects can accept a visitor.
class Visitable
{
public:
virtual ~Visitable() { }
virtual void accept_visitor(Visitor& visitor) = 0;
virtual void accept(Object& obj);
};
// A base class, to allow downcasting
class Object
{
protected:
virtual void _f() { }
};
// Our Visitor class, which will wrap our concrete visitor implementation
class Visitor
{
public:
Visitor(Object* obj);
// Base class for concrete visitors
template
class OfType : public Object
{
public:
void visit(V* visitable) {
D* derived = static_cast(this);
// "duck-typed" method; if our derived class does not have
// this method, compilation will fail.
derived->on_visit(visitable);
}
};
template
void visit(V* visitable);
private:
Object* m_obj;
};
Visitor::Visitor(Object* obj) : m_obj(obj) { }
template
void Visitor::visit(V* visitable) {
// check if our visitor is able to visit this instance
OfType* visitor = dynamic_cast* >(m_obj);
if (visitor) {
visitor->visit(visitable);
}
}
void Visitable::accept(Object& visitor) {
Visitor wrapped(&visitor);
accept_visitor(wrapped);
}
After the above interfaces are defined, create specific interfaces for a visitable object's visitor, then implement them in your concrete class:
class This;
class ThisVisitor : public Visitor::OfType
{
public:
virtual void on_visit(This* item) = 0;
};
class This : public Visitable
{
public:
void accept_visitor(Visitor& visitor) {
visitor.visit(this);
}
};
class That;
class ThatVisitor : public Visitor::OfType
{
public:
virtual void on_visit(That* item) = 0;
};
class That : public Visitable
{
public:
void accept_visitor(Visitor& visitor) {
visitor.visit(this);
}
};
class MyVisitor : public ThisVisitor, public ThatVisitor
{
public:
void on_visit(This* item) { printf("This!"); }
void on_visit(That* item) { printf("That!"); }
};
int main(int argc, const char* argv[] {
This item1;
That item2;
MyVisitor visitor;
item1.accept(visitor); // "This!"
item2.accept(visitor); // "That!"
}
You could also skip the visitor interfaces entirely and have your concrete visitor derive from OfType
directly, but I find using the former is better for extending your visitor as new classes are defined (That
should not care about who visits it as long as it is of type ThatVisitor
).