//////////////////////////////////////////////////////////////////////////////// // 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-Welsey Longman make no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// // Last update: May 19, 2002 #ifndef VISITOR_INC_ #define VISITOR_INC_ #include "Typelist.h" #include "HierarchyGenerators.h" namespace Loki { //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitor // The base class of any Acyclic Visitor //////////////////////////////////////////////////////////////////////////////// class BaseVisitor { public: virtual ~BaseVisitor() {} }; //////////////////////////////////////////////////////////////////////////////// // class template Visitor // Forward decleration //////////////////////////////////////////////////////////////////////////////// template class Visitor; namespace Private { // for some reason VC7 needs the base definition altough not in use template struct VisitorHelper1 { template struct In { typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result; }; }; template struct VisitorHelper2 { template struct In { typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result; }; }; template <> struct VisitorHelper1 { template struct In { typedef Visitor Result; }; }; template <> struct VisitorHelper2 { template struct In { private: template struct In1 { typedef Visitor Result; }; template<> struct In1 { struct Result {}; }; public: typedef typename In1::Result Result; }; }; template <> struct VisitorHelper1 { template struct In { struct Result { typedef R ReturnType; virtual ReturnType Visit(T&) = 0; }; }; }; template <> struct VisitorHelper2 { template struct In { struct Result {}; }; }; } // namespace Private //////////////////////////////////////////////////////////////////////////////// // class template Visitor // The building block of Acyclic Visitor //////////////////////////////////////////////////////////////////////////////// template class Visitor : public Private::VisitorHelper1 < typename TL::is_Typelist::type_tag > ::template In::Result , public Private::VisitorHelper2 < typename TL::is_Typelist::type_tag > ::template In::Result { public: typedef R ReturnType; }; //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitorImpl // Implements non-strict visitation (you can implement only part of the Visit // functions) //////////////////////////////////////////////////////////////////////////////// template class BaseVisitorImpl; namespace Private { // for some reason VC7 needs the base definition altough not in use template struct BaseVisitorImplHelper { template struct In { typedef typename T::ERROR_THIS_INSTANCE_SELECTED Result; }; }; template<> struct BaseVisitorImplHelper { template struct In { typedef BaseVisitorImpl Result; }; }; template<> struct BaseVisitorImplHelper { template struct In { struct Result {}; }; }; } // namespace Private template class BaseVisitorImpl : public Visitor , public Private::BaseVisitorImplHelper < typename TL::is_Typelist::type_tag > ::template In::Result { ASSERT_TYPELIST(TList); public: // using BaseVisitorImpl::Visit; virtual R Visit(typename TList::Head&) { return R(); } }; //////////////////////////////////////////////////////////////////////////////// // class template NonStrictVisitor // Implements non-strict visitation (you can implement only part of the Visit // functions) //////////////////////////////////////////////////////////////////////////////// template struct NonStrictVisitorUnit : public Base { typedef typename Base::ReturnType ReturnType; ReturnType Visit(T&) { return ReturnType(); } }; template class NonStrictVisitor : public GenLinearHierarchy< TList, NonStrictVisitorUnit, Visitor > { }; //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitable //////////////////////////////////////////////////////////////////////////////// template struct DefaultCatchAll { static R OnUnknownVisitor(Visited&, BaseVisitor&) { return R(); } }; //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitable //////////////////////////////////////////////////////////////////////////////// template < typename R = void, template class CatchAll = DefaultCatchAll > 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); } }; //////////////////////////////////////////////////////////////////////////////// // macro DEFINE_VISITABLE // Put it in every class that you want to make visitable (in addition to // deriving it from BaseVisitable //////////////////////////////////////////////////////////////////////////////// #define DEFINE_VISITABLE() \ virtual ReturnType Accept(BaseVisitor& guest) \ { return AcceptImpl(*this, guest); } //////////////////////////////////////////////////////////////////////////////// // class template CyclicVisitor // 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; virtual ~CyclicVisitor() {} template ReturnType GenericVisit(Visited& host) { Visitor& subObj = *this; return subObj.Visit(host); } }; //////////////////////////////////////////////////////////////////////////////// // macro DEFINE_CYCLIC_VISITABLE // Put it in every class that you want to make visitable by a cyclic visitor //////////////////////////////////////////////////////////////////////////////// #define DEFINE_CYCLIC_VISITABLE(SomeVisitor) \ virtual SomeVisitor::ReturnType Accept(SomeVisitor& guest) \ { return guest.GenericVisit(*this); } } // namespace Loki //////////////////////////////////////////////////////////////////////////////// // Change log: // March 20: add default argument DefaultCatchAll to BaseVisitable // June 20, 2001: ported by Nick Thurn to gcc 2.95.3. Kudos, Nick!!! //////////////////////////////////////////////////////////////////////////////// #endif // VISITOR_INC_