too few template-arguments-lists



  • Wäre es nicht schöner, wenn es

    static T* Instance;
    
       static T* getInstance(){
           if(!Instance){
              Instance = new T();
           }
           return Instance;
       }
    

    heißen würde?



  • Michael E. schrieb:

    Wäre es nicht schöner, wenn ...

    Damit könntest du Recht haben 😉 Hab den Code entsprechend angepasst.



  • pumuckl schrieb:

    Allgemein wirst du für alle anderen Instantiierungen von A aber dann noch den Fehler erhalten "undefined reference to A<C>::Instance" - weil du Instance eben nur für B definiert hast und für alle anderen möglichen Templateparameter nicht. Um das zu beheben könntest du einfach allgemein A<T>::Instance = NULL in A.hpp schreiben (hier in die hpp, weils ein Template und keine vollständige Spezialisierung ist). Die Spezialisierung für B kann dann entfallen.

    Ich habe diesen Vorschlag nun ausprobiert, da er meiner Meinung nach die sinnvollste und sauberste Lösung darstellt:

    // Datei A.hpp
    template <class T>
    class A{
    private:
       static A<T>* Instance;
    
       // Ctor und Copy-Ctor
    public:
       static A<T>* getInstance(){
           if(!Instance){
              Instance = new T();
              return Instance;
           }
           return Instance;
       }
    protected:
       // Irgendwelche Schnittstellendefinitionen
    };
    A<T>::Instance = NULL;
    

    Aber anschließend bekomme ich immer wieder die Fehlermeldung, dass "T" in diesem Gültigkeitsbereich nicht definiert wurde(mit Verweis auf die Zeile 19). Wie nehme ich nun die Initialisierung für Instance vor, ohne das Template spezialisieren zu müssen?


  • Administrator

    Wie wäre es mit:

    template<typename T>
    A<T>* A<T>::Instance = NULL;
    

    Aber sag mal, bist du sicher, dass es eine A<T> Instanz sein soll und nicht gleich eine T Instanz?

    Und wieso machst du dir das Leben nicht einfacher und machst sowas:

    // Datei A.hpp
    template <class T>
    class A{
       // Ctor und Copy-Ctor
    public:
       static A<T>* getInstance(){
           static A<T>* Instance = new T();
           return Instance;
       }
    protected:
       // Irgendwelche Schnittstellendefinitionen
    };
    

    Falls das Objekt nicht zu gross ist, könntest du es sogar direkt bauen lassen und nicht über den Heap gehen:

    static A<T>& getInstance(){
       static T Instance;
       return Instance;
    }
    

    Grüssli



  • Hi,

    Dravere schrieb:

    Wie wäre es mit:

    template<typename T>
    A<T>* A<T>::Instance = NULL;
    

    Jupp, funktioniert, danke. Und ich hatte mich tatsächlich die ganze Zeit gefragt, warum T undefiniert ist 😃
    Hier würde es tatsächlich auch reichen, nur eine Instanz vom Typ T zurückzugeben. Habs entsprechend geändert.

    Dravere schrieb:

    Und wieso machst du dir das Leben nicht einfacher und machst sowas:

    // Datei A.hpp
    template <class T>
    class A{
       // Ctor und Copy-Ctor
    public:
       static A<T>* getInstance(){
           static A<T>* Instance = new T();
           return Instance;
       }
    protected:
       // Irgendwelche Schnittstellendefinitionen
    };
    

    Hmm, wenn ich an dieser Stelle getInstance() zweimal aufrufe, was passiert dann mit dem ersten - auf dem Heap angelegten - T? Ich könnte dann doch theoretisch folgendes machen:

    typedef A<T> Singleton;
    static Singleton* foo = Singleton::getInstance();
    static Singleton* bar = Singleton::getInstance();
    // 2 verschiedene Instanzen von Singleton
    

    Vielleicht ist es aber schon zu spät, und ich raffe es nicht 😉



  • Nein, statische Initialisierungen passieren nur einmal pro Programmdurchlauf.

    Aber wieso auf dem Heap? Wer soll das dann freigeben? Ausserdem würde ich keinen Zeiger, sondern eine Referenz zurückgeben.



  • Nexus schrieb:

    Nein, statische Initialisierungen passieren nur einmal pro Programmdurchlauf.

    Okay, ich war gerade in dem Glauben, dass eine neue statische Variable innerhalb der Funktion generiert wird, was sich jetzt nach mehrmaliger Überlegung natürlich als falsch herausstellt 😃

    Nexus schrieb:

    Aber wieso auf dem Heap? Wer soll das dann freigeben? Ausserdem würde ich keinen Zeiger, sondern eine Referenz zurückgeben.

    In meinem Quellcode versteckt sich noch eine kleine statische Memberfunktion destroy(), die den Speicher am Ende des Programms wieder freigibt. 😉



  • Matzer schrieb:

    In meinem Quellcode versteckt sich noch eine kleine statische Memberfunktion destroy(), die den Speicher am Ende des Programms wieder freigibt. 😉

    Sehr heikel, sowas geht extrem schnell vergessen. Gerade wenn das Programm frühzeitig beendet wird und das Projekt wächst. Wieso nicht direkt im statischen Speicherbereich arbeiten oder wenigstens den Zeiger kapseln?

    Ach ja, Referenzen fände ich immer noch besser. 😉
    Hat es einen bestimmten Grund, wieso du Zeiger nimmst? Wenn du dauernd dereferenzierst, kann eine Referenz schöner sein. Aber ist auch ein wenig Geschmackssache... 🙂



  • Nexus schrieb:

    Matzer schrieb:
    In meinem Quellcode versteckt sich noch eine kleine statische Memberfunktion destroy(), die den Speicher am Ende des Programms wieder freigibt. 😉
    Sehr heikel, sowas geht extrem schnell vergessen. Gerade wenn das Programm frühzeitig beendet wird und das Projekt wächst. Wieso nicht direkt im statischen Speicherbereich arbeiten oder wenigstens den Zeiger kapseln?

    Momentan schreibe ich an einer GUI-Lib und um boost::asio dazu zu überreden, einen asynchronen Aufruf zu meinem globalen EventHandler zu starten, muss am Ende jedes Programms ungefähr sowas stehen:

    // irgendwo im Code
    boost::asio::io_service MsgHandler;
    //in main()
    MsgHandler.run();
    return 0;
    

    Natürlich ist der Aufruf von run in irgendeiner Klasse gekapselt. Da aber run() am Ende des Programms sowieso ausgeführt werden muss, übernimmt die kapselnde Klasse anschließend auch die Aufräumarbeiten, sobald die globale MessageLoop durchlaufen ist. Vergessen wird es also erstmal nicht 😉

    Nexus schrieb:

    ...oder wenigstens den Zeiger kapseln?

    kommt alles noch 🙂 Ich wollte es erstmal schaffen, auf Linux und Windows je ein Fenster zur Anzeige zu bringen (was mir vorhin auch gelungen ist muhaa). Deswegen wird in einigen Teilen des Codes noch mir rohen Zeigern rumhantiert. Ich wollte nur so schnell wie möglich zum Ziel. Das geht natürlich auf Kosten des Designs

    Nexus schrieb:

    Ach ja, Referenzen fände ich immer noch besser. 😉
    Hat es einen bestimmten Grund, wieso du Zeiger nimmst? Wenn du dauernd dereferenzierst, kann eine Referenz schöner sein. Aber ist auch ein wenig Geschmackssache... 🙂

    Der hartnäckigen Forderung nach einer Referenz werde ich natürlich nachkommen 😉 Ist an dieser Stelle wohl tatsächlich angebrachter.



  • Würd dir empfehlen, dieses buch zu holen:

    http://www.amazon.com/Modern-Design-Programming-Patterns-Depth/dp/0201704315

    Da gibt es ein größeres beispiel zu einer modernen gui lib, afaik. Falls es mal irgendwo hapert.


Anmelden zum Antworten