Undefined Reference bei statischer Methode / Template



  • template <class ResourceType>
    ResourceManager<ResourceType>::resourcemap = ResourceManager<ResourceType>::ResourceMap();
    

    Nach genauerem hinschauen fiel mir auf, dass der TYP von resourcemap bei der Definition fehlt!

    Korrekt müsste es also lauten:

    template <class ResourceType>
    ResourceManager<ResourceType>::ResourceMap ResourceManager<ResourceType>::resourcemap = ResourceManager<ResourceType>::ResourceMap();
    

    Wobei ich mir jetzt nicht 100% sicher bin, ob da noch ein typename davor gehört, schließlich ist es ResourceMap ein abhängiger Typ, aber an bestimmten Stellen darf man dann doch wieder kein typename spezifizieren oder so oder auch nicht und überhaupt. Strg+F7 war da immer viel komfortabler, als mir ein für alle Mal Klarheit zu verschaffen 😉

    Edit #2001: Wobei ich mich aber natürlich frage, warum du dem ein Standard-Konstruiertes Objekt zuweist, kannst du dir doch sparen.



  • Decimad schrieb:

    Wobei ich mir jetzt nicht 100% sicher bin, ob da noch ein typename davor gehört, schließlich ist es ResourceMap ein abhängiger Typ, aber an bestimmten Stellen darf man dann doch wieder kein typename spezifizieren oder so oder auch nicht und überhaupt.

    Ist es nicht einfach so, dass typename genau dann angegeben werden muss, wenn der Typ Member eines Templates ist, das noch nicht vollständig instanziiert wurde (sprich: das von Template-Parametern abhängt)? Sorry, ich kann es gerade nicht besser formulieren.

    // T = Template-Parameter
    typename std::vector<T>::iterator i;
    
    // int = festgelegter, bekannter Typ
    std::vector<int>::iterator i;
    

    Die Begründung macht eigentlich auch Sinn: Solange für T kein konkreter Typ eingesetzt wird, ist nicht klar, ob es sich beim abhängigen Member um einen Typ handelt. Daher typename zur Anweisung an den Compiler.



  • Ja, so wie du das da schreibst, ergibt es auf diabolische Art und Weise Sinn!

    Wobei ich mich jetzt hier nun gerade frage... Wie macht man eigentlich static's in eine template-Klasse? Die könnte ja in tausend Modulen instanziiert werden, mit Typen, die nur diese Module kennen... Warum habe ich mir darüber nie Gedanken gemacht?



  • Decimad schrieb:

    Die könnte ja in tausend Modulen instanziiert werden, mit Typen, die nur diese Module kennen...

    Ja, aber das trifft ja auf alle Templates zu, oder inwiefern sind static -Variablen hier speziell?



  • Naja, static-variablen brauchen ja einen Speicherplatz im ganzen Projekt sozusagen. Den Code für die Templates kann man ja in jedes Übersetzungseinheit basteln und darauf vertrauen, dass der Compiler in jeder Einheit kompatiblen Code erzeugt, sozusagen (da wäre also die Duplizierung nicht schlimm).



  • Also ich habe mal so ein bissl gegoogelt und dann einen Beitrag von jemandem gefunden, der aussagte, dass der Compiler im Falle von statischen Datenmembern in Klassentemplates (welche dann ja im Header auch definiert werden müssen), darauf aufpasst, dass für jede Kombination von Template-Parametern in einem Projekt nur eine Definition erzeugt wird. Da stellt sich mir die Frage, warum tut er das nicht auch bei Nicht-Template-Klassen?^^



  • Decimad schrieb:

    Da stellt sich mir die Frage, warum tut er das nicht auch bei Nicht-Template-Klassen?^^

    Wohl weil der Standard dagegen ist. Vieles wäre wahrscheinlich technisch realisierbar.

    Erlaubt C++0x nicht die Definition beliebiger statischer Member direkt innerhalb der Klasse? (Wobei das auch Nachteile hat, wenn man dadurch Abhängigkeiten in den Header verfrachtet.)



  • Passt jetzt vielleicht nicht 100% hier her, aber...: wie sieht es in C++0x mit inline initialisierten "static const" in einer Klasse aus?
    Laut dem aktuellen Standard muss man die ja nochmal ausserhalb der Klasse definieren. Was aber irgendwie keiner macht, weil es doof ist.
    Also so

    struct foo {
    	static const int c = 1234;
    };
    
    const int foo::c; // <- die Zeile die keiner schreibt, weil sie sowas von umsonst ist
    


  • Funtioniert wie gewohnt.



  • 314159265358979 schrieb:

    Funtioniert wie gewohnt.

    Sinnlose Antwort, wie gewohnt.



  • Wieder mal Löschviecher unterwegs.
    Danke!



  • Macht doch mal Bussi ihr beiden! Hilft doch nix 😉



  • Decimad schrieb:

    Macht doch mal Bussi ihr beiden! Hilft doch nix 😉

    Ich bin ruhig, solange ich nicht provoziert werde.



  • 314159265358979 schrieb:

    Wieder mal Löschviecher unterwegs.
    Danke!

    Ja, du lagst mit Deiner Antwort weit abseits.
    Du hättest analysieren sollen, inwiefern ein static const überhaupt ein Objekt ist, ob es Speicher hat, ob man damit alles machen kann, Funktionen aufrufen, Adressen oder Referenzen ziehen und so.



  • Es ging um die Initialisierung. Mehr nicht. Aber mir egal, lösch halt meine Posts, wenns dir Spaß macht.



  • OK, die Frage war vielleicht nicht ganz klar. Also nochmal.

    Der aktuelle Standard verlangt dass man integrale static const nochmal ausserhalb der Klasse definiert, auch wenn sie bereits "inline" definiert wurden. Und zwar in genau einer TU - genau so wie nicht "inline" definierte static const.

    Das nervt.

    Und daher macht es keiner (ich sehe es zumindest so-gut-wie nie).

    Die beiden grossen Compiler (GCC und MSVC) fressen das auch ohne weiteres, obwohl es laut Standard ein Fehler ist.

    Was funktioniert und was nicht ist mir daher auch einigermassen klar.

    Die Frage ist: erlaubt der neue Standard das jetzt offiziell, oder nicht?



  • If a static data member is of const literal type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

    Paragraph 9.4.2 Absatz 3

    Wenn ich das richtig gelesen habe, ist es immer noch erforderlich.



  • 314159265358979 schrieb:

    If a static data member is of const literal type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

    Paragraph 9.4.2 Absatz 3

    Wenn ich das richtig gelesen habe, ist es immer noch erforderlich.

    Ich fürchte, ich lese, daß man das member nicht in der UE definieren muß, solange man es nur als Konstante benutzt, wie in Arraygrößenangaben oder arithmetischen Ausdrücken. Also dürfen wir weitermachen wie bisher.
    Nur, wenn man es ODR-benutzt, muß man es auch noch definieren. Was ist ODR-benutzen?



  • Es tut mir leid die aktuelle Diskussion zu unterbrechen,
    aber ich bin mit der Korrektur meines Quellcodes trotz allem Genannten ein wenig überfordert.
    Kann mir jemand den korrigierten Quellcode aufschreiben?
    Vielen Dank,
    Adam S



  • Meine Lösung auf der ersten Seite, ergänzt um ein typename vor dem Rückgabetyp, vergleiche die Antwort auf meine Frage von Nexus.


Anmelden zum Antworten