compiler-fehler bei static member und überladenem operator()



  • folgender code:

    struct Foo
    {
        void operator() () {}
    };
    
    template<class T>
    struct Bar
    {
        static T t;
    };
    
    template<> Foo Bar<Foo>::t;
    
    int main()
    {
        Bar<Foo> b;
        b.t();
        // kein fehler mit:
        //b.t;
    }
    

    mit dem g++ 3.4.1 beschwert sich der linker, wenn man bei zeile19 b.t() aufruft:

    /tmp/ccgvCaHN.o(.text+0x1f): In function main': : undefined reference toBar<Foo>::t'

    so, als ob das objekt nirgends initialisiert würde. schreibt man in zeile14 dann

    template<> Foo Bar<Foo>::t();
    

    kommt:

    static.cpp:15: error: no member function `t' declared in `Bar<Foo>'

    .

    erst wenn man den copy-ctor verwendet, klappt es wieder:

    Foo cpy_obj;
    template<> Foo Bar<Foo>::t( cpy_obj );
    // aber nicht:
    // template<> Bar<Foo>::t( Foo() ); // funktions-fehler wie oben
    

    imho ein compilerfehler! ich bitte um kommentare.



  • struct foo
    {
    	void operator()( void )
    	{
    		std::cout << "foo::operator ()\n";
    	}
    };
    
    template< typename type >
    struct bar
    {
    	static type t;
    };
    
    template< typename type > type bar< type >::t;
    


  • das funzt, aber ich brauche die spezialisierung.



  • *push*



  • Habe es mit Version 3.4.5 getestet, funktioniert problemlos. Was mich allerdings etwas verwundert. Da der Member statisch ist, dürfte nur

    Bar<Foo>::t();
    

    zulässig sein.



  • @eadgseg
    Das ist kein Compiler-Bug sondern eine (böse) Falle in C++.
    Das hier:

    template<> Foo Bar<Foo>::t;
    

    ist eine sogenannte "non-defining out of class declaration". Für normale Klassen gibt es soetwas nicht und das Ganze wäre schlicht eine Definition von t. Für vollständige spezialisierte Templates (bzw. deren Member) sieht das aber anders aus. Zum einen muss eine solche Spezialisierung in jeder ÜE, in der sie verwendet wird sichtbar sein, gleichzeitig ist sie aber kein Template mehr.
    Würde die oben zitierte Syntax zu einer Definition führen, dann hättest du ein Problem: sobald mehr als eine ÜE die Spezialisierung verwendet, käme es zu einer Mehrfachdefinition von t.
    Aus diesem Grund besagt der C++ Standard, dass template<> Foo Bar<Foo>::t lediglich eine Deklaration ist.

    Das löst das "Mehrfachdefinition"-Problem, führt aber zu einem anderen: es gibt in C++ keine Syntax, die die Default-Initialisierung eines vollständig spezialisierten statischen Members zulässt. Du bist also auf Copy-Initialisierung angewiesen:

    template<> Foo Bar<Foo>::t = Foo();
    

    groovemaster schrieb:

    Habe es mit Version 3.4.5 getestet, funktioniert problemlos. Was mich allerdings etwas verwundert. Da der Member statisch ist, dürfte nur

    Bar<Foo>::t();
    

    zulässig sein.

    Wie kommst du darauf?

    class X {
    public:
     static int f();
    };
    
    int main() {
     X x;
     x.f();
    }
    

    Das ist legales C++ und x.f() ist in diesem Fall äquivalent zu X::f();



  • HumeSikkins schrieb:

    ..."non-defining out of class declaration"...

    😮 😮 😮 👍

    Wäre ich NIE drauf gekommen.
    und Du hast es auch noch so gut erklärt, dass ich es begriffen habe (glaube ich).
    Also ein Konflikt zwischen "vollständiger Spezialisierung" und "One-Definition-Rule"... hmmmm da werde ich noch ein wenig drüber nachdenken.

    Danke,

    Simon2.

    P.S.: Hast Du eine Kapitelangabe aus dem Standard darüber ?



  • Simon2 schrieb:

    P.S.: Hast Du eine Kapitelangabe aus dem Standard darüber ?

    14.7.3/15:

    An explicit specialization of a static data member of a template is a definition if the declaration includes an initializer; otherwise, it is a declaration. [Note: there is no syntax for the definition of a static data member of a template that requires default initialization.

    template<> X Q<int>::x;

    This is a declaration regardless of whether X can be default initialized (8.5). ]

    Hervorhebung von mir.



  • Ah, vielen Dank !

    Gruß,

    Simon2.



  • HumeSikkins schrieb:

    Wie kommst du darauf?

    Da bin ich ehrlich gesagt etwas baff. Habe nicht gedacht, dass ein static Member auch über eine Instanz angesprochen werden kann. Würde man wohl auch nicht vermuten, da solche Member kein this kennen.


Anmelden zum Antworten