CRTP und inner class: invalid forward declaration



  • Servus,

    ich habe ein Problem bei Verwendung des curiously recurring template patterns. Und zwar möchte ich über einen Basisklassenpointer eine Operation anstoßen können, die auf Daten zugreift, deren Format dem Basisklassenpointer nicht bekannt sein soll. Diese Daten sind als inner class in der abgeleiteten Klasse definiert.

    Hier mal der Code:

    template <typename CRTP>
    class Base {
    public:
        typedef typename CRTP::Metadata Meta;
        virtual void foo(Meta* meta) = 0;
    };
    
    class Derived: public Base<Derived> {
    public:
        class Metadata {
        public:
            void bar();
        };
    
        virtual void foo(Metadata* meta) {meta->bar();}
    };
    

    Fehlermeldung von gcc 4.4

    test_crtp.cpp: In instantiation of ‘Base<Derived>’:
    test_crtp.cpp:14:   instantiated from here
    test_crtp.cpp:10: error: invalid use of incomplete type ‘class Derived’
    test_crtp.cpp:14: error: forward declaration of ‘class Derived’
    

    Geht das generell nicht, da ich in Templates keine Annahmen über inner classes treffen darf, oder habe ich was übersehen?

    Gruß,
    Phil



  • class Derived: public Base<Derived> {
    public:
        class Metadata {
        public:
            void bar(){}
        };
    
        virtual void foo(Metadata* meta) {meta->bar();}
    };
    


  • Ein diff zwischen deinem Posting und meinem Code gibt 0 unterschiedliche Zeichen. Wie darf ich das verstehen? 🙂

    Phil



  • Nicht ganz. Schau nochmal genau. 😉



  • Sorry, ja.

    Hatte bei mir lokal nur in bar() noch ein cout drin, daher waren die geschweiften Klammern schon da.

    Fehlermeldung auch mit leeren geschweiften Klammern noch dieselbe wie vorher 😞



  • Hm, ist vielleicht nicht richtig, aber ich frage mal:
    Kann der Compiler überhaupt Base<Derived> instantiieren, obwohl ihm die Größe von Derived nicht bekannt ist? Das kann ja nicht klappen.



  • Ja, ich denke auch, dass das nicht geht, weil bei der Instanzierung der genaue Typ ja noch nicht bekannt ist. Allerdings ist es auch nicht unbedingt nötig, weil das base nur wissen muss, DASS es einen solchen Typen geben wird. Allerdings weiss Derived bei der Instanzierung selbst noch nicht einmal, dass es einen solchen Typen geben wird. Hier wäre eine Vorwärtsdeklaration für eine nested class notwendig, was IIRC nicht geht.
    Also eine sinnvolle Alternative wäre es ja den Typen einfach auszulagern und dann von Hand zu übergeben:

    template <typename CRTP, typename Meta>
    class Base {
    public:
        virtual void foo(Meta* meta) = 0;
    };
    
    class Metadata {
    public:
    	void bar();
    };
    
    class Derived: public Base<Derived, Metadata> {
    public:
    
        virtual void foo(Metadata* meta) {meta->bar();}
    };
    

    Das klappt ohne Probleme.


Anmelden zum Antworten