Using the Visitor Pattern with template derived classes

前端 未结 2 783
清酒与你
清酒与你 2020-12-16 08:36

I try to implement the Visitor pattern with templated derived classes

I work with gcc 4.5

here is the VisitorTemplate.hpp, I specialized Der

相关标签:
2条回答
  • 2020-12-16 09:19

    Your Derived class cannot use Visitor because it hasn't been defined yet (it was only forward declared, and is therefore an incomplete type).

    You can fix the compile error by putting the Visitor definition before Derived. You will also need to forward-declare Derived before defining Visitor:

    template <class T> class Derived;
    
    class Visitor {
    public:
        virtual void visit(Derived<string> *e) = 0;
    };
    
    template <class T>
    class Derived : public Base {
        //.... can call Visitor methods here ...
    };
    
    0 讨论(0)
  • 2020-12-16 09:33

    From Modern C++ - Design Generic Programming and Design Patterns Applied - Andrei Alexandrescu

    #include <iostream>
    
    class BaseVisitor
    {
        public:
            virtual ~BaseVisitor() {};
    };
    
    template <class T, typename R = int>
    class Visitor
    {
        public:
            virtual R visit(T &) = 0;
    };
    
    template <typename R = int>
    class BaseVisitable
    {
        public:
            typedef R ReturnType;
            virtual ~BaseVisitable() {};
            virtual ReturnType accept(BaseVisitor & )
            {
                return ReturnType(0);
            }
        protected:
            template <class T>
            static ReturnType acceptVisitor(T &visited, BaseVisitor &visitor)
            {
                if (Visitor<T> *p = dynamic_cast< Visitor<T> *> (&visitor))
                {
                    return p->visit(visited);
                }
                return ReturnType(-1);
            }
    
            #define VISITABLE() \
                virtual ReturnType accept(BaseVisitor &v) \
                    { return acceptVisitor(*this, v); }
    };
    
    
    /** example of use */
    class Visitable1 : public BaseVisitable<int>
    {
        /* Visitable accept one BaseVisitor */
        public:
            VISITABLE();
    };
    
    class Visitable2 : public BaseVisitable<int>
    {
        /* Visitable accept one BaseVisitor */
        public:
            VISITABLE();
    };
    
    class VisitorDerived : public BaseVisitor,
            public Visitor<Visitable1, int>,
            public Visitor<Visitable2, int>
    {
        public:
            int visit(Visitable1 & c)
            {
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }
            int visit(Visitable2 & c)
            {
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }
    };
    
    int main(int argc, char **argv)
    {
        VisitorDerived visitor;
        Visitable1 visitable1;
        Visitable2 visitable2;
    
        visitable1.accept(visitor);
        visitable2.accept(visitor);
    }
    

    Is possible to avoid dynamic_cast with CRTP pattern like:

    #include <iostream>
    
    class BaseVisitor
    {
        public:
            virtual ~BaseVisitor() {};
    };
    
    template <class T>
    class Visitor
    {
        public:
            virtual void visit(T &) = 0;
    };
    
    template <class Visitable>
    class BaseVisitable
    { 
        public:
            template <typename T>
            void accept(T & visitor)
            {
                visitor.visit(static_cast<Visitable &>(*this));
            }
    };
    
    /** example of use */
    class Visitable1 : public BaseVisitable<Visitable1>
    {
    };
    
    class Visitable2 : public BaseVisitable<Visitable2>
    {
    };
    
    class VisitorDerived : public BaseVisitor, 
                           public Visitor<Visitable1>,
                           public Visitor<Visitable2>
    {
        public:
            void visit(Visitable1 & c)
            {
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }
            void visit(Visitable2 & c)
            {
                std::cout << __PRETTY_FUNCTION__ << std::endl;
            }
    };
    
    int main(int argc, char **argv)
    {
        VisitorDerived visitor;
        Visitable1 visitable1;
        Visitable2 visitable2;
    
        visitable1.accept<VisitorDerived>(visitor);
        visitable2.accept<VisitorDerived>(visitor);
    }
    
    0 讨论(0)
提交回复
热议问题