Implementing the visitor pattern using C++ Templates
我一直试图通过使用C++模板来实现访问者模式来减少代码中的样板数量。到目前为止,我想到了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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)); } }; |
visitable的每个子类如下:
1 2 | class Mesh : public Object, public Visitable<Mesh> {}; class Text : public Object, public Visitable<Text> {}; |
最后,访客看起来是这样的:
1 | class Renderer : public Visitor<Mesh>, public Visitor<Text> {} |
到现在为止,一直都还不错。。。现在的问题是:
1 2 3 4 5 6 7 | 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); } } |
我需要以某种方式强制转换为visitable,以便调用accept(),但显然我不知道什么是t。或者,我不能向可见模板添加虚拟accept(),因为我不知道它应该采用什么参数。
任何C++模板大师都知道如何做这个工作吗?
型
这可以用变量模板在C++ 11中完成。从皮特的回答继续:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | // 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)); } }; |
号
1 2 | class Mesh : public Object, public VisitableImpl<Mesh, Mesh, Text> {}; class Text : public Object, public VisitableImpl<Text, Mesh, Text> {}; |
a
1 | class Renderer : public Visitor<Mesh, Text> {}; |
。
不清楚您的
1 2 3 4 5 6 7 | 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); } } |
型
除了允许任意访问者删除访问者之外,您的basevisitor不为您做任何事情。相反,您希望为访问者提供一个基类,它提供可以对其调用的所有不同的
为此,您可以使用类型列表来定义访问者可以接受的类型,使用类型列表作为基本visitee类,并将类型列表作为参数添加到visitee实现中。
示例草图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | // 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 { }; 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)); } }; |
型
我还需要一个模板化的访问者模式,并且能够创建一个不涉及变量类型或类型列表使用的解决方案。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | // 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<typename D, typename V> class OfType : public Object { public: void visit(V* visitable) { D* derived = static_cast<D*>(this); //"duck-typed" method; if our derived class does not have // this method, compilation will fail. derived->on_visit(visitable); } }; template<typename D, typename V> void visit(V* visitable); private: Object* m_obj; }; Visitor::Visitor(Object* obj) : m_obj(obj) { } template<typename D, typename V> void Visitor::visit(V* visitable) { // check if our visitor is able to visit this instance OfType<D,V>* visitor = dynamic_cast<OfType<D,V>* >(m_obj); if (visitor) { visitor->visit(visitable); } } void Visitable::accept(Object& visitor) { Visitor wrapped(&visitor); accept_visitor(wrapped); } |
。
在定义了上述接口之后,为可访问对象的访问者创建特定的接口,然后在具体类中实现它们:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | class This; class ThisVisitor : public Visitor::OfType<ThisVisitor, This> { public: virtual void on_visit(This* item) = 0; }; class This : public Visitable { public: void accept_visitor(Visitor& visitor) { visitor.visit<ThisVisitor>(this); } }; class That; class ThatVisitor : public Visitor::OfType<ThatVisitor, That> { public: virtual void on_visit(That* item) = 0; }; class That : public Visitable { public: void accept_visitor(Visitor& visitor) { visitor.visit<ThatVisitor>(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!" } |
。
您也可以完全跳过访客界面,让您的具体访客直接从