Konstanten mit Templates



  • Im Prinzip möchte ich gerne, das der Klassentyp eine Id erhält auf die ich dann reagieren kann.

    class B:public A<double,1>{};
    class C:public A<float,2>{};
    
    void foo(int id)
    {
      const int q = B::Id; //ok
    
      switch(id)
      {
        case B::Id://error C2051
          //...
          break;
        case C::Id://error C2051
         //...
          break;
      }   
    }
    

    Ich bin soweit gekommen

    template<class T,const int i> class A
    {
      static const int Id;
    };
    template<class T,const int i> const int A<T,i>::Id(i);
    

    Der Compiler meckert bei switch/case immer

    error C2051: case expression not constant
    

    kann man das irgendwie lösen?



  • eine statische Membervariable ist keine Compilezeit-Konstante (besonders wenn sie nicht direkt initialisiert wurde) - und damit nicht als case-Marke geeignet.
    (für die Initialisierung von lokalen Konstanten kann der Compiler auch Laufzeit-Konstanten (und sogar Variablen) verwenden)

    Eventuell könntest du mit einem enum arbeiten - dessen Wert(e) ist eine Compilezeit-Konstante:

    template<typename T,int i>
    class A
    {
      enum{Id = i};
    };
    


  • template<class T, const int i> class A //das const hier kannst du dir sparen, i ist sowieso nicht veränderbar.
    {
      static const int Id = i;
    };
    

  • Mod

    CStoll schrieb:

    eine statische Membervariable ist keine Compilezeit-Konstante

    queer_boy's Variante funktioniert.

    (besonders wenn sie nicht direkt initialisiert wurde)

    ja, was denn nun? und was soll "nicht direkt initialisiert" überhaupt bedeuten?

    Eventuell könntest du mit einem enum arbeiten - dessen Wert(e) ist eine Compilezeit-Konstante:

    template<typename T,int i>
    class A
    {
      enum{Id = i};
    };
    

    Ja, Aufzählungskonstanten können in konstanten Ausdrücken auftreten, das gilt aber eben auch für statische integrale Member, die mit konstanten Ausdrücken initialisiert wurden. Das Ganze hat offenbar speziell etwas mit Templats zu tun, statische Member eines Templates werden nicht instantiiert (insbesondere findet deren Initialisierung nicht statt, solange die Member nicht in einer Weise gebraucht werden, die die Existenz der Definition voraussetzt). Das bedeutet, dass selbst eine explizite Instantiierung des Members nicht hilft (eine explizite Spezialisierung hilft dagegen - dann haben wir es ja nicht mehr mit einer template-Deklaration zu tun). Weil ein case-Label einen konstanten Ausdruck voraussetzt, und das Auftreten eines statischen integralen Members in einem solchen Ausdruck keine "Benutzung" des Members im Sinne von 3.2/2 darstellt, bewirkt es keine Instantiierung desselben - obwohl wir für die Berechnung des Ausdrucks auf diese Instantiierung angewiesen sind.
    -- Das ist bis jetzt meine Interpretation des Problems - die mich selbst allerdings nicht besonders überzeugt 😉



  • camper schrieb:

    CStoll schrieb:

    eine statische Membervariable ist keine Compilezeit-Konstante

    queer_boy's Variante funktioniert.

    (besonders wenn sie nicht direkt initialisiert wurde)

    ja, was denn nun? und was soll "nicht direkt initialisiert" überhaupt bedeuten?

    Damit meinte ich, daß idefix die Variable außerhalb der Klassenfunktion initialisiert hatte. (und afaik unterstützt auch nicht jeder Compiler queer_boy's Variante)



  • Das ist richtig Panne, das ich da nicht selber drauf kam.

    template<class T, const int i> class A 
    {
      static const int Id = i;
    };
    

Anmelden zum Antworten