Fehler mit g++ und templates



  • Das ist bei Templates nicht so einfach. Der Compiler weiß ja nicht dass es bei jedem T beim geerbten GladeWrapper<T> ein widget gibt. Lösung: qualifizieren. Entweder this->widget oder GladeWrapper<T>::widget



  • Danke für die Antwort, werde ich gleich mal testen.

    Die Logik dahinter ist mir allerdings nicht klar.
    Wieso soll der compiler bei templates nichts von den Elementen der Überklasse wissen?
    Ich leite doch explizit von Base<T> ab.

    Ist der Fehler standardkonform und MSVC nur gnädig oder liegts an g++?



  • C14 schrieb:

    Ist der Fehler standardkonform und MSVC nur gnädig oder liegts an g++?

    Das kann man meist recht gut mit dem Comeau ausprobieren (sofern der Code kein Geschäftsgeheimnis ist).

    Soviel mir bekannt ist der Fehler durchaus Standardkonform, und der MSVC ist in einigen Punkten noch recht gnädig (Auch wenn er sich wirklich massiv dem Standard angenähert hat - hoffe das wird er auch in Zukunft weiterführen).

    cu André



  • C14 schrieb:

    Danke für die Antwort, werde ich gleich mal testen.

    Die Logik dahinter ist mir allerdings nicht klar.
    Wieso soll der compiler bei templates nichts von den Elementen der Überklasse wissen?
    Ich leite doch explizit von Base<T> ab.

    Stimmt. Aber der Compiler weiß ja nicht, wie Base<T> zum Zeitpunkt der Instantiierung des Templates aussieht! Beispiel:

    template <class T>
    struct Base
    {
      int i;
    };
    
    template <class T>
    struct Derived : public Base<T>
    {
      void foo()
      {
        i = 5;
      }
    };
    
    template<>
    struct Base<int>
    {
      int y;
    };
    
    int main()
    {
      Derived<float> df; 
      df.foo(); //ok
    
      Derived<int> di;
      di.foo(); //ähm. was war noch gleich i??????
    }
    

    Zusammengefasst: Der Compiler kann nicht sicher sein, wie Base<T> zum Zeitpunkt der Instantiierung von Derived<T> aussehen wird. Deshalb kann er nicht in Base<T> schauen, um herauszufinden dass i ein Member von Base<T> ist. Oder auch nicht. Oder vielleicht. Darum müssen Member von Basisklassentemplates in abgeleiteten Klassentemplates explizit qualifiziert werden.



  • Hi pumuckl,

    magst Du Deinen Code mal kurz überarbeiten? Ich vermute, Du meintest

    template <class T>
    struct Derived : Base<T>
    ...
    
    template<>
    struct Base<int>
    {
    ...
    

    Oder?
    (Bin nicht so sattelfest bei templates)

    Aber auch das Argument

    pumuckl schrieb:

    ...Der Compiler kann nicht sicher sein, wie Base<T> zum Zeitpunkt der Instantiierung von Derived<T> aussehen wird. ...

    leuchtet nir noch nicht so richtig ein, weil der Compiler
    a) die (template-)Instantiierung doch IIRC erst bei der (Objekt-)Instantiierung fällig wird ... und zu dem Zeitpunkt kennt er die Spezialisierung doch schon.
    b) Muss der Compiler nicht sowieso schon "alles" über eine Klasse wissen, bevor er sie als "definiert" betrachten kann?
    Ich meine - er stellt doch zum Zeitpunkt der Instantiierung auch fest, wenn irgendwelche anderen Member(z.B. Funktionen, Konstruktoren, ...) fehlen.
    Gerade bei der Objekterzeugung muss er doch sowieso wissen, welche Konstruktoren (inkl. Basisklassen und Member) er aufrufen muss...

    Ich kann verstehen, wenn diese "Weitsicht" zu schwer zu implementieren sei und sie deshalb aus dem Standard genommen worden wäre, aber dass das ein prinzipielles Problem ist, hat sich mir immer noch nicht erschlossen.

    Gruß,

    Simon2.



  • Simon2 schrieb:

    Hi pumuckl,

    magst Du Deinen Code mal kurz überarbeiten? Ich vermute, Du meintest
    [...]
    Oder?

    Richtig. Danke. Done 🙂



  • pumuckl schrieb:

    ...Done 🙂

    Nicht ganz ... das zweite base muss auch noch groß. 😉

    ... und ich habe oben noch eine Frage reineditiert (während Du schon meinen ersten Entwurf gelesen hast).

    Gruß,

    Simon2.



  • Simon2 schrieb:

    pumuckl schrieb:

    ...Der Compiler kann nicht sicher sein, wie Base<T> zum Zeitpunkt der Instantiierung von Derived<T> aussehen wird. ...

    leuchtet nir noch nicht so richtig ein, weil der Compiler
    a) die (template-)Instantiierung doch IIRC erst bei der (Objekt-)Instantiierung fällig wird ... und zu dem Zeitpunkt kennt er die Spezialisierung doch schon.
    b) Muss der Compiler nicht sowieso schon "alles" über eine Klasse wissen, bevor er sie als "definiert" betrachten kann?
    Ich meine - er stellt doch zum Zeitpunkt der Instantiierung auch fest, wenn irgendwelche anderen Member(z.B. Funktionen, Konstruktoren, ...) fehlen.
    Gerade bei der Objekterzeugung muss er doch sowieso wissen, welche Konstruktoren (inkl. Basisklassen und Member) er aufrufen muss...

    Im Grunde ist es festgelegt, dass Templates in zwei Phasen compiliert werden. IIRC geschieht die Syntaxprüfung und einiges mehr in der ersten Phase, z.B. die Auflösung des i im Beispiel oben. Der Compiler stellt dann schonmal fest, ob es sich bei i um eine Variable im Scope der Klasse oder um irgendeine globale Variable handelt. Die erste Phase geschieht beim Parsen des Template Codes, wo eben noch nicht bekannt ist welche Spezialisierung von Base nun zur Basisklasse wird. Daher kann diese Auflösung des Scopes nicht in die Basisklassentemplates schauen. Mit Base<T>::i sage ich ihm also dass i in der Basisklasse zu finden ist, bzw. mit this->i, dass es irgendwo in der Klassenhierarchie zu finden ist. Bei der eigentlichen Instantiierung von Base<int> erkennt er dann erst in Phase 2, dass es dieses i garnicht gibt und beschwert sich. AFAIK ist MSVC deshalb so gnädig, weil die beiden Phasen zu einer zusammengelegt wurden und erst zum Zeitpunkt der Instantiierung stattfinden, wo der Compiler schon genau sagen kann welche Spezialisierung zur Basisklasse wird und ob/wo er i findet.



  • Hmmm,

    ein wenig seltsam finde ich, dass der Std (wenn ich Dich recht verstanden habe) so eine "Ablaufbeschreibung" festlegt. Ich hätte gedacht, dass er eher festlegt, was zu machen ist und weniger wie.
    Das scheint mir ja tatsächlich eher Thema (wenn nicht gar ein Zugeständnis an die Machbarkeit des) "Compilerbau" zu sein.
    Wobei mich schon überrascht, wieso MS das hinbekommt.

    Ändert sich an dieser Stelle eigentlich etwas beim C++0x?

    Gruß,

    Simon2.




Anmelden zum Antworten