//////////////////////////////////////////////////////////////////////////////// // The Loki Library // Copyright (c) 2001 by Andrei Alexandrescu // This code accompanies the book: // Alexandrescu, Andrei. "Modern C++ Design: Generic Programming and Design // Patterns Applied". Copyright (c) 2001. Addison-Wesley. // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The author or Addison-Wesley Longman make no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// #ifndef LOKI_VISITOR_INC_ #define LOKI_VISITOR_INC_ // $Id$ /// \defgroup VisitorGroup Visitor #include #include namespace Loki { //////////////////////////////////////////////////////////////////////////////// /// \class BaseVisitor /// /// \ingroup VisitorGroup /// The base class of any Acyclic Visitor //////////////////////////////////////////////////////////////////////////////// class BaseVisitor { public: virtual ~BaseVisitor() {} }; //////////////////////////////////////////////////////////////////////////////// /// \class Visitor /// /// \ingroup VisitorGroup /// The building block of Acyclic Visitor /// /// \par Usage /// /// Defining the visitable class: /// /// \code /// class RasterBitmap : public BaseVisitable<> /// { /// public: /// LOKI_DEFINE_VISITABLE() /// }; /// \endcode /// /// Way 1 to define a visitor: /// \code /// class SomeVisitor : /// public BaseVisitor // required /// public Visitor, /// public Visitor /// { /// public: /// void Visit(RasterBitmap&); // visit a RasterBitmap /// void Visit(Paragraph &); // visit a Paragraph /// }; /// \endcode /// /// Way 2 to define the visitor: /// \code /// class SomeVisitor : /// public BaseVisitor // required /// public Visitor /// { /// public: /// void Visit(RasterBitmap&); // visit a RasterBitmap /// void Visit(Paragraph &); // visit a Paragraph /// }; /// \endcode /// /// Way 3 to define the visitor: /// \code /// class SomeVisitor : /// public BaseVisitor // required /// public Visitor::Type> /// { /// public: /// void Visit(RasterBitmap&); // visit a RasterBitmap /// void Visit(Paragraph &); // visit a Paragraph /// }; /// \endcode /// /// \par Using const visit functions: /// /// Defining the visitable class (true for const): /// /// \code /// class RasterBitmap : public BaseVisitable /// { /// public: /// LOKI_DEFINE_CONST_VISITABLE() /// }; /// \endcode /// /// Defining the visitor which only calls const member functions: /// \code /// class SomeVisitor : /// public BaseVisitor // required /// public Visitor, /// { /// public: /// void Visit(const RasterBitmap&); // visit a RasterBitmap by a const member function /// }; /// \endcode /// /// \par Example: /// /// test/Visitor/main.cpp //////////////////////////////////////////////////////////////////////////////// template class Visitor; template class Visitor { public: typedef R ReturnType; typedef T ParamType; virtual ~Visitor() {} virtual ReturnType Visit(ParamType&) = 0; }; template class Visitor { public: typedef R ReturnType; typedef const T ParamType; virtual ~Visitor() {} virtual ReturnType Visit(ParamType&) = 0; }; //////////////////////////////////////////////////////////////////////////////// // class template Visitor (specialization) // This specialization is not present in the book. It makes it easier to define // Visitors for multiple types in a shot by using a typelist. Example: // // class SomeVisitor : // public BaseVisitor // required // public Visitor // { // public: // void Visit(RasterBitmap&); // visit a RasterBitmap // void Visit(Paragraph &); // visit a Paragraph // }; //////////////////////////////////////////////////////////////////////////////// template class Visitor, R, false> : public Visitor, public Visitor { public: typedef R ReturnType; // using Visitor::Visit; // using Visitor::Visit; }; template class Visitor, R, false> : public Visitor { public: typedef R ReturnType; using Visitor::Visit; }; template class Visitor, R, true> : public Visitor, public Visitor { public: typedef R ReturnType; // using Visitor::Visit; // using Visitor::Visit; }; template class Visitor, R, true> : public Visitor { public: typedef R ReturnType; using Visitor::Visit; }; //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitorImpl // Implements non-strict visitation (you can implement only part of the Visit // functions) //////////////////////////////////////////////////////////////////////////////// template class BaseVisitorImpl; template class BaseVisitorImpl, R> : public Visitor , public BaseVisitorImpl { public: // using BaseVisitorImpl::Visit; virtual R Visit(Head&) { return R(); } }; template class BaseVisitorImpl, R> : public Visitor { public: virtual R Visit(Head&) { return R(); } }; //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitable //////////////////////////////////////////////////////////////////////////////// template struct DefaultCatchAll { static R OnUnknownVisitor(Visited&, BaseVisitor&) { return R(); } }; //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitable //////////////////////////////////////////////////////////////////////////////// template < typename R = void, template class CatchAll = DefaultCatchAll, bool ConstVisitable = false > class BaseVisitable; template class CatchAll> class BaseVisitable { public: typedef R ReturnType; virtual ~BaseVisitable() {} virtual ReturnType Accept(BaseVisitor&) = 0; protected: // give access only to the hierarchy template static ReturnType AcceptImpl(T& visited, BaseVisitor& guest) { // Apply the Acyclic Visitor if (Visitor* p = dynamic_cast*>(&guest)) { return p->Visit(visited); } return CatchAll::OnUnknownVisitor(visited, guest); } }; template class CatchAll> class BaseVisitable { public: typedef R ReturnType; virtual ~BaseVisitable() {} virtual ReturnType Accept(BaseVisitor&) const = 0; protected: // give access only to the hierarchy template static ReturnType AcceptImpl(const T& visited, BaseVisitor& guest) { // Apply the Acyclic Visitor if (Visitor* p = dynamic_cast*>(&guest)) { return p->Visit(visited); } return CatchAll::OnUnknownVisitor(const_cast(visited), guest); } }; //////////////////////////////////////////////////////////////////////////////// /// \def LOKI_DEFINE_VISITABLE() /// \ingroup VisitorGroup /// Put it in every class that you want to make visitable /// (in addition to deriving it from BaseVisitable) //////////////////////////////////////////////////////////////////////////////// #define LOKI_DEFINE_VISITABLE() \ virtual ReturnType Accept(::Loki::BaseVisitor& guest) \ { return AcceptImpl(*this, guest); } //////////////////////////////////////////////////////////////////////////////// /// \def LOKI_DEFINE_CONST_VISITABLE() /// \ingroup VisitorGroup /// Put it in every class that you want to make visitable by const member /// functions (in addition to deriving it from BaseVisitable) //////////////////////////////////////////////////////////////////////////////// #define LOKI_DEFINE_CONST_VISITABLE() \ virtual ReturnType Accept(::Loki::BaseVisitor& guest) const \ { return AcceptImpl(*this, guest); } //////////////////////////////////////////////////////////////////////////////// /// \class CyclicVisitor /// /// \ingroup VisitorGroup /// Put it in every class that you want to make visitable (in addition to /// deriving it from BaseVisitable //////////////////////////////////////////////////////////////////////////////// template class CyclicVisitor : public Visitor { public: typedef R ReturnType; // using Visitor::Visit; template ReturnType GenericVisit(Visited& host) { Visitor& subObj = *this; return subObj.Visit(host); } }; //////////////////////////////////////////////////////////////////////////////// /// \def LOKI_DEFINE_CYCLIC_VISITABLE(SomeVisitor) /// \ingroup VisitorGroup /// Put it in every class that you want to make visitable by a cyclic visitor //////////////////////////////////////////////////////////////////////////////// #define LOKI_DEFINE_CYCLIC_VISITABLE(SomeVisitor) \ virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest) \ { return guest.GenericVisit(*this); } } // namespace Loki #endif // end file guardian