//////////////////////////////////////////////////////////////////////////////// // 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: Oct 27, 2002 // // The original visitor implementation depends heavily on the possibility // to return an expression of type "cv void" from a functions with a return // type of cv void (6.6.3). // Unfortunately the MSVC 6.0 does not allow that. Because I could not think // of any transparent workaround I decided to create a set of complete new // classes for the void-case. // Of course this is a very unattractive solution :-( // If you know of a better solution, please let me know. // // The MSVC 6.0 does not allow void to be a default value for a template parameter. // I therefore changed all defaults to int. #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; // class for the void-case template class BaseVisitorImplVoid; 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 BaseVisitorImplVoidHelper { template struct In { typedef typename T::ERROR_WRONG_SPECIALIZATION_SELECTED Result; }; }; template<> struct BaseVisitorImplVoidHelper { template struct In { typedef BaseVisitorImplVoid Result; }; }; template<> struct BaseVisitorImplVoidHelper { template struct In { struct Result {}; }; }; template struct BaseVisitorImplVoidWrap { struct Dummy {}; typedef typename BaseVisitorImplVoidHelper < 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 class BaseVisitorImpl : public Visitor, public Private::BaseVisitorImplWrap::Result { ASSERT_TYPELIST(TList); public: // using BaseVisitorImpl::Visit; virtual R Visit(typename TList::Head&) { return R(); } }; // class for the void-case template class BaseVisitorImplVoid : public Visitor, public Private::BaseVisitorImplVoidWrap::Result { ASSERT_TYPELIST(TList); public: // using BaseVisitorImpl::Visit; virtual void Visit(typename TList::Head&) {} }; //////////////////////////////////////////////////////////////////////////////// // class template DefaultCatchAll //////////////////////////////////////////////////////////////////////////////// template struct DefaultCatchAll { static R OnUnknownVisitor(Visited&, BaseVisitor&) { return R(); } }; // template template parameter workaround. // use Wrapper-Classes like this to instantiate BaseVisitable struct DefaultCatchAllWrapper { template struct In { typedef DefaultCatchAll type; }; }; template struct DefaultCatchAllVoid { static R OnUnknownVisitor(Visited&, BaseVisitor&) {} }; struct DefaultCatchAllVoidWrapper { template struct In { typedef DefaultCatchAllVoid 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(); } }; struct NonStrictVisitorUnitWrapper { template struct In { typedef NonStrictVisitorUnit type; }; }; template class NonStrictVisitor : public GenLinearHierarchy< TList, NonStrictVisitorUnitWrapper, Visitor > { }; template struct NonStrictVisitorUnitVoid : public Base { typedef void ReturnType; ReturnType Visit(T&) { } }; struct NonStrictVisitorUnitVoidWrapper { template struct In { typedef NonStrictVisitorUnitVoid type; }; }; template class NonStrictVisitorVoid : public GenLinearHierarchy< TList, NonStrictVisitorUnitWrapper, Visitor > { }; //////////////////////////////////////////////////////////////////////////////// // class template BaseVisitable //////////////////////////////////////////////////////////////////////////////// template < typename R = int/* = void */, class CatchAll = DefaultCatchAllWrapper > 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) { typedef ApplyInnerType2::type CatchA; // Apply the Acyclic Visitor if (Visitor* p = dynamic_cast*>(&guest)) { return p->Visit(visited); } return CatchA::OnUnknownVisitor(visited, guest); } }; // class for the void-case template < class CatchAll = DefaultCatchAllVoidWrapper > class BaseVisitableVoid { public: typedef void ReturnType; virtual ~BaseVisitableVoid() {} virtual ReturnType Accept(BaseVisitor&) = 0; protected: // give access only to the hierarchy 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); } CatchA::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); } #define DEFINE_VISITABLE_VOID() \ virtual void Accept(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 //////////////////////////////////////////////////////////////////////////////// template class CyclicVisitor : public Visitor { public: typedef R ReturnType; // using Visitor::Visit; template ReturnType GenericVisit(Visited& host) { Visitor& subObj = *this; return subObj.Visit(host); } }; template class CyclicVisitorVoid : public Visitor { public: typedef void ReturnType; // using Visitor::Visit; template ReturnType GenericVisit(Visited& host) { Visitor& subObj = *this; 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); } #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 //////////////////////////////////////////////////////////////////////////////// #endif // VISITOR_INC_