Externe Variable als Template-Argument



  • Hi,

    ich habe hier ein sehr fragwürdig programmiertes SDK zu einem Sensor vor mir, welches mir Probleme beim Kompilieren bereitet. Ich konnte die Problematik auf folgendes Minimalbeispiel reduzieren:

    struct Descriptor
    {
    };
    
    template <Descriptor const& D>
    struct Foo
    {
    	int bar()
    	{
    		return 0;
    	}
    };
    
    extern "C"
    {
    	extern Descriptor const global_descr;
    }
    
    template<> inline int Foo<global_descr>::bar()
    {
    	return 1;
    }
    
    int main()
    {
    	return 0;
    }
    

    Problem: Es kompiliert unter GCC 4.3 bis 4.8 und 5.1 bis 5.2 sowie Clang, jedoch nicht unter GCC 4.9.*, welcher jedoch leider mein Zielcompiler ist. Hier ist die Fehlermeldung vom GCC 4.9.2:

    main.cpp:20:23: error: prototype for ‘int Foo<D>::bar() [with const Descriptor& D = (* & global_descr)]’ does not match any in class ‘Foo<(* & global_descr)>’
     template<> inline int Foo<global_descr>::bar()
                           ^
    main.cpp:8:6: error: candidate is: int Foo<D>::bar() [with const Descriptor& D = (* & global_descr)]
      int bar()
          ^
    

    Ich verstehe nicht wirklich, was hier vor sich geht. Woher kennt der Compiler überhaupt die Adresse der externen Variable schon beim Kompilieren und kann so die explizite Template-Spezialisierung durchführen? Ich dachte, das wird erst vom Linker aufgelöst... Wieso kompiliert das ganze also mit den meisten GCC-Versionen? Wieso ausgerechnet mit der 4.9er nicht? Und was kann ich unter minimalinvasiven Gesichtspunkten unternehmen, damit es auch mit dem 4.9er tut? Die Library ist riesig und das Pattern zieht sich überall durch 😞

    Grüße


  • Mod

    bei mir

    g++ (Gentoo Hardened 4.9.3 p1.1, pie-0.6.2) 4.9.3
    

    compiliert das.


  • Mod

    Bloops schrieb:

    Woher kennt der Compiler überhaupt die Adresse der externen Variable schon beim Kompilieren und kann so die explizite Template-Spezialisierung durchführen?

    Die kennt er nicht und das muss er auch nicht. Der Compiler merkt sich einfach das Symbol, auf das verwiesen wird (ggf. +Offset, sofern legale Zeigerarithmetik verwendet wird). Und selbst der Linker kennt ja nicht in jedem Falle die finalen Adressen - die werden ggf. erst durch den Loader fixiert.



  • Ich konnte es nur mit GCC 4.9.0, 4.9.1 und 4.9.2 testen, welche alle drei nicht funktioniert haben. Habe nach deinem Hinweis mal in den GCC-Bugs geschaut, welche für 4.9.3 gefixt wurden. Und siehe da: Bug #63658. Na wenn der Bug-Report mal nicht von dem SDK-Entwickler ist - man beachte die Ähnlichkeit zu meinem Minimalbeispiel 😉

    Dann muss ich also wohl einfach warten, bis der GCC 4.9.3 zu meiner Ubuntu-Version durchdiffundiert ist...


Anmelden zum Antworten