Fehler bei Visitor-Template nach Loki-Library



  • Hallo zusammen,

    ich versuche mir gerade das Visitor-Template-Pattern nach Loki nachzubauen, komme aber an einer Stelle nicht weiter. Vielleicht könnt ihr mir helfen.

    Hier die Quelle nach der ich es versuche nachzubauen:
    http://loki-lib.sourceforge.net/html/a00685.html

    Ich möchte so einen "Multi-Visitor" bauen, wie ihn Loki definiert:

    class SomeVisitor : 
    public BaseVisitor // required
    public Visitor<LOKI_TYPELIST_2(RasterBitmap, Paragraph)>
    {
    public:
    void Visit(RasterBitmap&); // visit a RasterBitmap
    void Visit(Paragraph &);   // visit a Paragraph
    };
    

    Soweit ich dies verstehe ist mit C++11 nicht mehr alles nötig, daher hier mein Versuch (leider in mehreren Teilen, h und cc Dateien habe ich mal zusammengefasst):

    Visitor.h

    class AMessage;
    class BMessage;
    
    template <class T, bool ConstVisit = false >
    class Visitor;
    
    template <typename T>
    class Visitor<T, false> {
    public:
    
        virtual ~Visitor() {}
        virtual void visit(const T &) = 0;
    };
    
    template<class... T> struct type_list {};
    
    class VisitorImpl :
    public Visitor<type_list<AMessage, BMessage> , false> {
    public:
    
        virtual void visit(const AMessage &){
            std::cout << "getting a AMessage!\n";
        }
    
        virtual void visit(const BMessage &){
            std::cout << "getting a BMessage!\n";
        }
    };
    

    Message.h

    #include "Visitor.h"
    
    template <class T>
    class Message {
    public:
        typedef Visitor<T> VisitorType;
        virtual void accept(VisitorType & handler) = 0;
    };
    

    AMessage.h (BMessage ist analog):

    #include "Message.h"
    class AMessage : public Message<VisitorImpl> {
        void accect(VisitorType & handler){
           std::cout << "accept handler in A\n";
           handler.visit(*this);
        }
    };
    

    Als Fehler erhalte ich:

    AMessage.cc:15:19: error: no viable conversion from 'AMessage' to 'const VisitorImpl'
        handler.visit(*this);
                      ^~~~~
    Visitor.h:50:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'AMessage' to 'VisitorImpl &&' for 1st argument
    class VisitorImpl :
          ^
    Visitor.h:50:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'AMessage' to 'const VisitorImpl &' for 1st argument
    class VisitorImpl :
          ^
    Visitor.h:34:33: note: passing argument to parameter here
        virtual void visit(const T &) = 0;
    

    Ich verstehe nicht, wieso der beim visit ein VisitorImpl haben will, statt eine AMessage und warum er im Fehler zu Visitor springt, statt zu VisitorImpl.

    Jemand nen Tipp?

    Vielen Dank schon einmal.

    sven_



  • In dem Code stimmen mehrere Sachen nicht so ganz. Fangen wir mal oben an:

    class VisitorImpl : public Visitor<type_list<AMessage, BMessage>
    

    So einfach mit der type_list wie du das hingeschrieben hast ist es wohl nicht. Wie ich das sehe musst du deine type_list zerpflücken und dafür sorgen, dass deine VisitorImpl am Ende von Visitor<AMessage> und Visitor<BMessage> erbt. Das ist wohl der schwierigste Teil. Wenn ich zum testen einfach mal class VisitorImpl : public Visitor<AMessage> schreibe und die Fehler weiter unten korrigiere compiliert es immerhin und sollte auch das tun was du möchtest.

    template <class T>
    class Message {
    public:
        typedef Visitor<T> VisitorType;
        virtual void accept(VisitorType & handler) = 0;
    };
    

    Das sollte wohl typedef T VisitorType; heißen.

    void accect(VisitorType & handler)
    

    Tippfehler.



  • Hallo Sebi707,

    ich habe mein Code wie folgt geändert:

    Visitor.h

    ...
    class VisitorImpl :
    public Visitor<AMessage, true> {
    public:
        virtual void visit(const AMessage &);
    };
    

    Message.h

    template <class T, bool ConstVisit = false>
    class Message;
    
    template <class T>
    class Message<T, false> {
    public:
        typedef T VisitorType;
        virtual ~Message() {}
        virtual void accept(VisitorType &) = 0;
    };
    

    AMessage.h

    class AMessage : public Message<VisitorImpl> {
    
        virtual ~AMessage();
    
        virtual void accect(VisitorType & handler);
    };
    

    main.cc

    int
    main(int argc, char** argv) {
    
        AMessage a;
        VisitorImpl visitor;
        visitor.visit(&a);
        return 0;
    }
    

    Diese ergibt beim compilen:

    main.cc:24:14: error: variable type 'AMessage' is an abstract class
        AMessage a;
                 ^
    ./Message.h:31:18: note: unimplemented pure virtual method 'accept' in 'AMessage'
    

    Ich versteh den Fehler nicht. Kannst mir noch nen Tip geben???



  • Du kannst keine Klassen mit virtuellen Funktionen instanzieren, du musst die erst ableiten und die Funktion implementieren.



  • Hallo Bengo,

    AMessage ist doch eine Ableitung? Und implementiert doch virtual void accect(VisitorType & handler), oder sehe ich dies falsch???

    Gruß



  • Ja schon aber du hast einen Tippfehler in AMessage, wie ich schon geschrieben habe. accect != accept



  • Hallo zusammen,

    ach Gott. Der Fehler sitzt immer vor dem Rechner 🙄 Peinlich. 😃 😃 😃

    Nun läuft meine Testcode. Erst mal cool. Allerdings eine Frage habe ich noch. Die VisitiorImpl ist jetzt:

    class VisitorImpl :
    public Visitor<AMessage, false> {
    public:
    
        virtual void visit(AMessage &);
        virtual void visit(const AMessage &);
    
        virtual void visit(BMessage &);
        virtual void visit(const BMessage &);
    
    };
    

    meine main.cc

    int
    main(int argc, char** argv) {
    
        AMessage a;
        BMessage b;
        VisitorImpl visitor;
        visitor.visit(a);
        visitor.visit(a);
        visitor.visit(a);
        visitor.visit(a);
        visitor.visit(a);
        visitor.visit(b);
        return 0;
    }
    

    Warum geht dies für BMessage??? Wo ich doch nur public Visitor<AMessage, false> definiert habe??? Heißt die Definitionen in VisitorImpl sind keine Überladungen von virtual void visit(ParamType &) = 0; in Visitor??

    Gruß

    sven_



  • sven_ schrieb:

    Heißt die Definitionen in VisitorImpl sind keine Überladungen von virtual void visit(ParamType &) = 0; in Visitor??

    Du musst dir einfach denken wie dein Code aussieht nachdem die ganzen Templates eingesetzt wurden. Dann sollte klar werden, dass VisitorImpl von einer Klasse erbt, die eine pure virtual Funktion void visit(const AMessage &) definiert. Das hindert dich aber nicht daran noch weitere Funktionen in deiner VisitorImpl zu definieren, etwa für BMessage . Mir ist gerade sowieso nicht klar warum die Visitor Klasse virtual inheritance braucht. Wenn du nur

    class VisitorImpl {
    public:
        void visit(AMessage &);
        void visit(const AMessage &);
    
        void visit(BMessage &);
        void visit(const BMessage &);
    };
    

    schreiben würdest, geht dein Beispiel auch. Aber ich bin gerade nicht so in dem Visitor Pattern drin, also kann sein das man doch die ganze Vererbungsgeschichte für irgendwas braucht.



  • Nicht, dass ich mich großartig damit befasst habe, aber ist Loki seit C++0x nicht zu großen Teilen obsolet? Ein Großteil der Konzepte von Loki sind längst Teil der Sprache. Ich denke, die Library würde zum großen Teil verdampfen, wenn man Variadic Templates und Tuple benutzt.



  • Hallo zusammen,

    nun ich habe auf Loki nur zugegriffen, wegen der pure virtuel Methoden für die Message, weil es direkt eigentlich ja nicht geht.

    Die pure virtual im Visitor waren eigentlich gedacht, dass der User gezwungen wird, die entsprechenden visit-Methoden zu implementieren. Aber da muss ich auch sagen, ohne ist vielleicht eleganter. Muss man es halt in die Doku reinschreiben, statt es dem Compiler zu überlassen. Ansonsten müsste ich wohl noch die Visitor für Head, Tail bzw. Head, null_Type angeben, vermute ich. Das ergibt aber unschöne Vererbungen. Daher glaube ich, dass ich mich dem Vorschlag von sebi707 anschließe.

    Vielen Dank für Eure Hilfe! Es ist nen großartiges Forum hier! Vielen Dank an alle!

    sven_


Anmelden zum Antworten