//////////////////////////////////////////////////////////////////////////////// // 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. //////////////////////////////////////////////////////////////////////////////// // Last update: Feb 23, 2003 // // This new of visitor.h handles void returns transparently. See // readme.txt for an explanation of the used technique. // However there are still two sets of macros. One for return type = void // (DEFINE_VISITABLE_VOID, DEFINE_CYCLIC_VISITABLE_VOID) and one for return // type != void (DEFINE_VISITABLE, DEFINE_CYCLIC_VISITABLE) // // If you prefer the old version of visitor.h which uses a different set of // visitor classes for the return type void, define the macro // USE_VISITOR_OLD_VERSION. // // The MSVC 6.0 does not allow void to be a default value for a template parameter. // I therefore changed all defaults to int. #ifdef USE_VISITOR_OLD_VERSION #include "VisitorOld.h" #else #ifndef VISITOR_INC_ #define VISITOR_INC_ #include "Typelist.h" #include "HierarchyGenerators.h" #include "MSVC6Helpers.h" namespace Loki { //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitor // The base class of any Acyclic Visitor //////////////////////////////////////////////////////////////////////////////// class BaseVisitor { public: virtual ~BaseVisitor() {} }; //////////////////////////////////////////////////////////////////////////////// // class template Visitor // The building block of Acyclic Visitor //////////////////////////////////////////////////////////////////////////////// template class Visitor; //////////////////////////////////////////////////////////////////////////////// // 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 Visitor // { // public: // void Visit(RasterBitmap&); // visit a RasterBitmap // void Visit(Paragraph &); // visit a Paragraph // }; //////////////////////////////////////////////////////////////////////////////// namespace Private { // helper for Visitor's the left base class template struct VisitorImplLeft { template struct In { typedef typename TList::ERROR_WRONG_SPECIALIZATION_SELECTED Result; }; }; // helper for Visitor's the right base class template struct VisitorImplRight { template struct In { typedef typename TList::ERROR_WRONG_SPECIALIZATION_SELECTED Result; }; }; // simulates specialization // class Visitor template <> struct VisitorImplLeft { template struct In { struct Result { typedef R ReturnType; virtual ReturnType Visit(T&) = 0; }; }; }; // simulates the left base class for the specialization // class Visitor, R> template <> struct VisitorImplLeft { template struct In { typedef Visitor Result; }; }; template <> struct VisitorImplRight { template struct In { struct Result {}; }; }; // simulates the right base class for the specialization // class Visitor, R> template <> struct VisitorImplRight { template struct In { typedef Visitor Result; }; }; template <> struct VisitorImplRight { template struct In { struct Result {}; }; }; // MSVC 6.0 will complain if we try to let Visitor inherit // directly from VisitorImplLeft/VisitorImplRight template struct VisitorImplLeftWrap { struct Dummy{}; typedef typename VisitorImplLeft < TL::Private::IsTypelist::type_id == TL::Private::AtomList_ID ? TL::Private::Typelist_ID : TL::Private::IsTypelist::type_id >::template In::Result TempType; typedef VC_Base_Workaround Workaround; typedef Workaround::LeftBase Result; }; template struct VisitorImplRightWrap { struct Dummy{}; typedef typename VisitorImplRight < TL::Private::IsTypelist::type_id >::template In::Result TempType; typedef VC_Base_Workaround Workaround; typedef Workaround::LeftBase Result; }; } template class Visitor : public Private::VisitorImplLeftWrap::Result, public Private::VisitorImplRightWrap::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 { template struct BaseVisitorImplHelper { template struct In { typedef typename T::ERROR_WRONG_SPECIALIZATION_SELECTED Result; }; }; template<> struct BaseVisitorImplHelper { template struct In { typedef BaseVisitorImpl Result; }; }; template<> struct BaseVisitorImplHelper { template struct In { struct Result {}; }; }; template struct BaseVisitorImplWrap { struct Dummy {}; typedef typename BaseVisitorImplHelper < TL::Private::IsTypelist:: type_id == TL::Private::AtomList_ID ? TL::Private::Typelist_ID : TL::Private::IsTypelist::type_id >::template In::Result TempType; typedef VC_Base_Workaround Workaround; typedef Workaround::LeftBase Result; }; template struct BaseVisitorImplBase : public Visitor, public Private::BaseVisitorImplWrap::Result { ASSERT_TYPELIST(TList); virtual R Visit(typename TList::Head&) { return R(); } }; template struct BaseVisitorImplVoidBase : public Visitor, public Private::BaseVisitorImplWrap::Result { ASSERT_TYPELIST(TList); virtual R Visit(typename TList::Head&) { } }; } template class BaseVisitorImpl : public Select < Private::IsVoid::value, Private::BaseVisitorImplVoidBase, Private::BaseVisitorImplBase >::Result { ASSERT_TYPELIST(TList); public: // using BaseVisitorImpl::Visit; }; //////////////////////////////////////////////////////////////////////////////// // class template DefaultCatchAll //////////////////////////////////////////////////////////////////////////////// namespace Private { } template struct DefaultCatchAll { static R OnUnknownVisitor(Visited&, BaseVisitor&) { return R(); } }; template struct DefaultCatchAllVoid { static R OnUnknownVisitor(Visited&, BaseVisitor&) { } }; // template template parameter workaround. // use Wrapper-Classes like this to instantiate BaseVisitable struct DefaultCatchAllWrapper { template struct In { typedef typename Select::value, DefaultCatchAllVoid, DefaultCatchAll >::Result type; }; }; //////////////////////////////////////////////////////////////////////////////// // 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 struct NonStrictVisitorUnitVoid : public Base { typedef typename Base::ReturnType ReturnType; ReturnType Visit(T&) {} }; struct NonStrictVisitorUnitWrapper { template struct In { typedef typename B::ReturnType R; typedef typename Select::value, NonStrictVisitorUnitVoid, NonStrictVisitorUnit >::Result type; }; }; template class NonStrictVisitor : public GenLinearHierarchy< TList, NonStrictVisitorUnitWrapper, Visitor > { }; //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitable //////////////////////////////////////////////////////////////////////////////// #include namespace Private { template class BaseVisitableBase { typedef R ReturnType; protected: template static ReturnType AcceptImpl(T& visited, BaseVisitor& guest) { typedef ApplyInnerType2::type CatchA; // Apply the Acyclic Visitor if (Visitor* p = dynamic_cast*>(&guest)) { return p->Visit(visited); } return CatchA::OnUnknownVisitor(visited, guest); } }; template class BaseVisitableVoidBase { typedef R ReturnType; protected: template static ReturnType AcceptImpl(T& visited, BaseVisitor& guest) { typedef ApplyInnerType2::type CatchA; // Apply the Acyclic Visitor if (Visitor* p = dynamic_cast*>(&guest)) { p->Visit(visited); return; } CatchA::OnUnknownVisitor(visited, guest); } }; } template < typename R = int/* = void */, class CatchAll = DefaultCatchAllWrapper > class BaseVisitable : public Select::value, Private::BaseVisitableVoidBase, Private::BaseVisitableBase >::Result { public: typedef R ReturnType; virtual ~BaseVisitable() {} virtual ReturnType Accept(BaseVisitor&) = 0; }; //////////////////////////////////////////////////////////////////////////////// // 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(Loki::BaseVisitor& guest) \ { return AcceptImpl(*this, guest); } #define DEFINE_VISITABLE_VOID() \ virtual ReturnType Accept(Loki::BaseVisitor& guest) \ { AcceptImpl(*this, guest); } //////////////////////////////////////////////////////////////////////////////// // class template CyclicVisitor // Put it in every class that you want to make visitable (in addition to // deriving it from BaseVisitable //////////////////////////////////////////////////////////////////////////////// namespace Private { template class CyclicVisitorBase : public Visitor { public: template ReturnType GenericVisit(Visited& host) { Visitor& subObj = *this; return subObj.Visit(host); } }; template class CyclicVisitorVoidBase : public Visitor { public: template ReturnType GenericVisit(Visited& host) { Visitor& subObj = *this; subObj.Visit(host); } }; } template class CyclicVisitor : public Select::value, Private::CyclicVisitorVoidBase, Private::CyclicVisitorBase >::Result { public: typedef R ReturnType; // using Visitor::Visit; }; //////////////////////////////////////////////////////////////////////////////// // 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); } #define DEFINE_CYCLIC_VISITABLE_VOID(SomeVisitor) \ virtual void Accept(SomeVisitor& guest) \ { 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!!! // Oct 27, 2002: ported by Benjamin Kaufmann to MSVC 6.0 // Feb 23, 2003: Removed special visitor classes for return type void. // Added Loki:: qualification to Accept's Paramter (in the macro) B.K. //////////////////////////////////////////////////////////////////////////////// #endif // VISITOR_INC_ #endif