www.pudn.com > Loki.rar > Visitor.h


//////////////////////////////////////////////////////////////////////////////// 
// 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_