Konstanter Ausdruck in Klassendekl. != konstanter Ausdruck in Funktion?



  • Hallo,
    folgendes funktioniert: (achtung pseudocode!)

    funktion()
    {
      static const size_type golden_ratio =
        static_cast<size_type>(0.5 * (1 + std::sqrt(5.0)) *
          std::numeric_limits<size_type>::max());
    }
    

    folgendes geht nicht:

    class A
    {
     static const size_type golden_ratio = wie oben;
    };
    

    gcc-4.1.1 sagt mir 'std::sqrt() cannot appear in a constant-expression'.

    Standard Kenner bitte helft mir 🙂

    Hat der Compiler recht? Oder soll ich ein Bug melden?



  • mach es doch so

    struct foo { static const size_t golden_ratio; };
    const size_t foo::golden_ratio = std::sqrt(5.0) // usw usw ;
    

    btw: ob es standardkonform ist weiss ich nicht 🕶



  • hmm tatsaechlich, so funktioniert es! also doch ein Compiler Bug?
    Sollte ja eigentlich aufs selbe hinauslaufen.



  • DerDieDu schrieb:

    hmm tatsaechlich, so funktioniert es! also doch ein Compiler Bug?
    Sollte ja eigentlich aufs selbe hinauslaufen.

    warum? die definition eines statischen members sollte doch immmer ausserhalb der klasse erfolgen.



  • Das gilt aber nur fuer Variablen die keine integralen Typen sind. Ein int oder auch size_t sollte eigentlich funktionieren. Wenn ich in der Deklaration golden_ratio = 3; setze dann kompiliert es wieder.



  • DerDieDu schrieb:

    Das gilt aber nur fuer Variablen die keine integralen Typen sind. Ein int oder auch size_t sollte eigentlich funktionieren. Wenn ich in der Deklaration golden_ratio = 3; setze dann kompiliert es wieder.

    ich weiss das es geht aber ist es auch korrekt 🙄



  • Ok, folgendes habe ich auf der gcc mailing liste gefunden, es wird der Standard zitiert:

    > If a static data member is of const integral or const enumeration
    > type, its declaration in the class definition can specify a
    > constant-initializer which shall be an integral constant expression
    > (5.19). In that case, the member can appear in integral constant
    > expressions within its scope. The member shall still be defined in a
    > namespace scope if it is used in the program and the namespace scope
    > definition shall not contain an initializer.

    Na gut, der Compiler hat recht!


  • Mod

    DerDieDu schrieb:

    static_cast<size_type>(0.5 * (1 + std::sqrt(5.0)) *
          std::numeric_limits<size_type>::max());
    

    ist kein konstanter ausdruck, sonern ein ganz normaler (nicht-konstanter) ausdruck, der zur initialisierung einer konstanten genutzt wird. die initialisierung einer statischen integralen memberkonstanten in deren deklaration setzt allerdings einen integralen konstanten ausdruck voraus. abschnitt 5.19 des standards definiert den begriff 'konstaner ausdruck'.



  • Nun, das ueberraschende war fuer mich, dass es eben diese Einschraenkung bezueglich statischer Konstanten in Klassen gibt. Ich habe einfach die Konstante aus einer Memberfunktion in die Klassendeklaration verschoben und ging davon aus, dass es gehen wuerde!



  • DerDieDu schrieb:

    Nun, das ueberraschende war fuer mich, dass es eben diese Einschraenkung bezueglich statischer Konstanten in Klassen gibt. Ich habe einfach die Konstante aus einer Memberfunktion in die Klassendeklaration verschoben und ging davon aus, dass es gehen wuerde!

    Weil Du durch "Copy&Paste" aus einem Etwas ein ganz anderes gemacht hast... 😉
    Du hast aus
    A einem "function local static" (wird zur Laufzeit vor dem ersten Aufruf der Funktion initialisiert => NICHT als Compilezeitausdruck (z.B. arraygrenze) verwendbar. Dass Du da const vorschreibst, ändert nichts dran, sondern bedeutet nur, dass Du innerhalb der Funktion diesen Wert nicht verändern willst/darfst.
    B ein "constant static member (without adress)" gemacht, das zur Compilezeit initialisiert wird und damit auch für Compilezeitausdrücke verwendbar ist.

    Der Knackpunkt ist, dass Du Funktionsaufruf verwendest (sqrt()), der nicht vom Compiler wegoptimiert werden kann .... stell' Dir einfach mal vor, sqrt(5.0) lieferte bei jedem Aufruf einen anderen Wert (was bei dem "echten" sqrt() besser nicht vorkommen sollte, aber das weiß der Compiler ja nicht) - das würde A keinen Abbruch tun (wäre weiter nur einmal initialisiert + innerhalb der Funktion nicht veränderbar), aber B könnte es nicht mehr erfüllen.

    Gruß,

    Simon2.


Log in to reply