Lokale Variable im Konstruktor eines Klassen-Templates?



  • Hallo,

    das folgende Programm bekomme ich einfach nicht compiliert. Nachdem ich nun schon lange Zeit nach einer Lösung gesucht habe, hoffe ich, daß hier jemand weiß, was eigentlich das Problem ist.

    #include <stdio.h>
    
    template <class T>
    class A
    {
    public:
      A()
      {
        void * x = NULL;
        //printf("%p", x);   // laesst sich nur mit dieser Zeile compilieren
      };
    };
    
    int main(void)
    {
    	A<int>();
    	return 0;
    }
    

    Ich verwende GCC 4.8.4 20140725 (release) [ARM/embedded-4_8-branch revision 213147]. Der GCC wirft keine Fehlermeldung aus. Interessanterweise tritt das Problem bei Microsoft Visual Studio 2012 11.0.61030.00 nicht auf.


  • Mod

    ThomasN schrieb:

    das folgende Programm bekomme ich einfach nicht compiliert.

    aha.

    ThomasN schrieb:

    Der GCC wirft keine Fehlermeldung aus.

    sondern?

    ThomasN schrieb:

    Interessanterweise tritt das Problem bei Microsoft Visual Studio 2012 11.0.61030.00 nicht auf.

    Welches Problem?



  • camper schrieb:

    sondern?
    Welches Problem?

    Ich hatte gemeint, daß der GCC nur einen Fehler anzeigt, aber keinen Hinweis auf dessen Ursache gibt (Das hatte ich leider mißverständlich formuliert). Der GCC wirft die folgende Meldung aus:

    In instantiation of 'A::A() [with T = int]': 
        required from here
    

    und markiert die Zeile 16 im obigen Programm mit einem Fehler (roter Kreis mit weißem Kreuz). Das Programm läuft aber trotzdem. Da ein Fehler gemeldet wird, traue ich ihm aber nicht.



  • Du betrachtest nur die halbe Meldung vom Compiler.

    test.cc: In instantiation of ‘A<T>::A() [with T = int]’:
    test.cc:16:12:   required from here
    test.cc:9:12: warning: unused variable ‘x’ [-Wunused-variable]
         void * x = NULL;
    

  • Mod

    ThomasN schrieb:

    camper schrieb:

    sondern?
    Welches Problem?

    Ich hatte gemeint, daß der GCC nur einen Fehler anzeigt, aber keinen Hinweis auf dessen Ursache gibt (Das hatte ich leider mißverständlich formuliert). Der GCC wirft die folgende Meldung aus:

    In instantiation of 'A::A() [with T = int]': 
        required from here
    

    und markiert die Zeile 16 im obigen Programm mit einem Fehler (roter Kreis mit weißem Kreuz). Das Programm läuft aber trotzdem. Da ein Fehler gemeldet wird, traue ich ihm aber nicht.

    Das ist die letzte Zeile einer langen Meldung. Und der GCC markiert bestimmt gar nichts, das macht deine IDE, die vielleicht auch den Rest der Fehlermeldung irgendwo versteckt.

    Vermutlich ist das eine Warnung wegen unbenutzter Variablen.



  • SeppJ schrieb:

    Vermutlich ist das eine Warnung wegen unbenutzter Variablen.

    Vielen Dank für Eure Tipps 🙂 Ich habe daraufhin noch etwas weiter probiert.
    Wenn man #pragma GCC diagnostic ignored "-Wunused-variable" einfügt, verschwindet die Fehlermeldung. Allerdings sind diese Warnungen dann wohl im ganzen Modul ausgeschaltet.
    Wenn man (void)x in den Konstruktor einfügt, verschwindet die Fehlermeldung auch. Sie ist dann nur lokal in dieser Funktion ausgeschaltet.
    Gut, dann bin ich beruhigt. Danke nochmals.



  • Warum nicht das Problem beheben (die Variable x rausschmeissen) anstatt einen Riesenaufwand betreiben um die Fehlermeldungen auszuschalten?



  • wurzelsepp schrieb:

    Warum nicht das Problem beheben (die Variable x rausschmeissen)

    Das obige Programmfragment ist aus einem größeren Programm entstanden, das ich soweit wie möglich abgespeckt habe, um die Fehlermeldung in einfacher Weise zu demonstrieren. Im Konstruktor des größeren Programms wird jedoch tatsächlich etwas Sinnvolles getan. Es wird ein binärer Operator abgerufen, die Variable aber nicht weiter benutzt. So kam die Fehlermeldung zustande.



  • ?? Wenn du die Variable als Operand eines binären Operators verwendest, benutzt du die doch auch. Also gibts auch diese Warnung nicht.



  • Der Programmcode hat so ausgesehen:

    template <class TCOutput>
    CSubMenu<TCOutput>::CSubMenu(string Name, string Help) : CMenuItem<TCOutput>(Name, Help)
    {
      CSubMenu<TCOutput> & subMenu = *this + 
        new CHelp<TCOutput>() +
        new COneMenueLevelUp<TCOutput>();
      (void)subMenu;                                              // to avoid warning 'unused variable 'subMenu' [-Wunused-variable]'
    }
    

    Du hast recht 🙂 Das geht einfacher:

    template <class TCOutput>
    CSubMenu<TCOutput>::CSubMenu(string Name, string Help) : CMenuItem<TCOutput>(Name, Help)
    {
      *this + 
        new CHelp<TCOutput>() +
        new COneMenueLevelUp<TCOutput>();
    }
    

    Manchmal sieht man halt den Wald vor lauter Bäumen nicht mehr 😉


  • Mod

    *this + 
        new CHelp<TCOutput>() + 
        new COneMenueLevelUp<TCOutput>();
    

    wtf?



  • Das Programm ist eine proprietäre Shell für ein Echtzeitsystem auf einem Mikrocontroller. Die Shell hat ein Menü (CSubMenu). Jedes Menü hat Einträge (CMenuItem), die Befehle (CCommand) oder weitere Untermenüs (CSubMenu) sein können. Mit der Instanziierung eines neuen Untermenüs wird automatisch der Hilfe-Befehl (new CHelp) und der Befehl, eine Menüeebene höher zu gehen, (new COneMenueLevelUp) für dieses Untermenü hinzugefügt. Daher erfolgt es in dessen Konstruktor. Das Hinzufügen von Einträgen zum Untermenü (*this) erledigt der binäre Operator + (CSubMenu<TCOutput> & operator+(CMenuItem<TCOutput> * menuItem). Die Shell ist generisch, d.h. sie hat keine Kenntnis, auf welchem Weg sie die Eingabe des Benutzers erhält und wie ihre Antworten zum Benutzer gelangen (seriell, JTAG-Adapter, Telnet, ...). Beim Instanziieren eines Ein-/Ausgabekanals parametriert er die Shell mit dem Funktionsobjekt TCOutput. Es stellt die Ausgabe-Funktionalität zur Verfügung. Denn nur der Ein-/Ausgabekanal kennt die technischen Details. Das Shell-Modul stellt nur die eigentliche Basisfunktionalität der Shell zur Verfügung (Befehle und Untermenüs anzeigen, Hilfe anzeigen, Menüebene hoch und runter gehen, Befehl ausführen). Erst durch Hinzufügen von Befehlen und Untermenüs wird sie mit Leben gefüllt. Befehle werden durch Ableiten von CCommand definiert (Informationen zu Tasks und Interrupts, Tracer-Meldungen, ...). So kann die Shell beliebig erweitert und für unterschiedliche Anwendungsfälle eingesetzt werden.



  • Arcoth schrieb:

    *this +
        new CHelp<TCOutput>() +
        new COneMenueLevelUp<TCOutput>();
    

    wtf?

    ThomasN schrieb:

    ... Das Hinzufügen von Einträgen zum Untermenü (*this) erledigt der binäre Operator + (CSubMenu<TCOutput> & operator+(CMenuItem<TCOutput> * menuItem).

    Die missbräuchliche Verwendung des Operators + stiftet Verwirrung. Normalerweise ändert dieser Operator keinen seiner Operanden (a + b // ändert weder a noch b) und somit würden die mit new erzeugten Instanzen im Nirwana landen. Der Operator += (oder this->append(...)) wäre wohl verständlicher. Allerdings kann man sich die Schnittstellen mit denen man arbeiten muss nicht immer aussuchen.



  • osdt schrieb:

    Der Operator += (oder this->append(...)) wäre wohl verständlicher.

    Vielen Dank für den Tipp 🙂 Ich habe es geändert:

    *this += new CHelp<TCOutput>();
        *this += new COneMenueLevelUp<TCOutput>();
    

    Wenn mehrere Leute über den Code schauen, wird die Softwarequalität einfach besser 😉



  • Ich weiß nicht. Finde ich immer noch nicht so schön. Muss es denn unbedingt ein überladener Operator sein? Was spricht denn gegen append? Dann spart man sich auch das explizite Aufschreiben von this:

    append(new CHelp<TCOutput>());
    append(new COneMenueLevelUp<TCOutput>());
    

Log in to reply