Klassen-Enum mit Konstanten?



  • Folgende Situation bekomme ich nicht kompiliert:

    class A {
    public:
    enum Adressen { Eins = m_base, Zwei = m_base + m_offset, Drei = m_base + 2 * m_offset };
    };
    

    m_base und m_offset sind Konstanten, die zur Compilezeit bekannt sind. Meine Versuche diese Variablen als "const int m_base" oder "static const int m_base" Klassenvariablen zu deklarieren haben den Compiler bei der Enumeration nie zufrieden gestellt.

    Wie löse ich das 😕 ?



  • Was mir noch einfällt: Was ist der zugrunde liegende Typ eines enums? Ein int? Ein unsigned int? Könnte ich auch "long" Adressen angeben oder würde da etwas abgeschnitten werden?

    Theoretisch wäre ja sogar der C-Typ "long long" in einem enum denkbar 😕 😕


  • Mod

    Aufzaehlung schrieb:

    Folgende Situation bekomme ich nicht kompiliert:

    Sollte es aber. Du machst etwas falsch. Zeig ein vollständiges Beispiel und nenn die Fehlermeldungen.

    Aufzaehlung schrieb:

    Was mir noch einfällt: Was ist der zugrunde liegende Typ eines enums? Ein int? Ein unsigned int? Könnte ich auch "long" Adressen angeben oder würde da etwas abgeschnitten werden?

    c++98 schrieb:

    The underlying type of an enumeration is an integral type that can represent all the enumerator values defined in the enu-
    meration. If no integral type can represent all the enumerator values, the enumeration is ill-formed. It is implementation-
    defined which integral type is used as the underlying type for an enumeration except that the underlying type shall not
    be larger than int unless the value of an enumerator cannot fit in an int or unsigned int. If the enumerator-list
    is empty, the underlying type is as if the enumeration had a single enumerator with value 0. The value of sizeof()
    applied to an enumeration type, an object of enumeration type, or an enumerator, is the value of sizeof() applied to
    the underlying type.

    In C++11 wurde vieles aktualisiert. Man kann nun angeben, welches der unterliegende Typ sein soll und enums können auch eigene Typen werden, die nicht mehr implizt von und nach int konvertiert werden können. Details findest du in jeder C++11-Einführung.

    Theoretisch wäre ja sogar der C-Typ "long long" in einem enum denkbar 😕 😕

    In strengem C++98: Nein, siehe oben. Nutz mal einen aktuellen Compiler, der long long kennt.



  • Wie komme ich an die Standardefinitionen? Dann kann ich sowas auch mal selber nachschlagen. Kostet der?

    Zum Problem: Es geht definitiv nicht mit const int und static int geht auch nur dann, wenn die Initialisierung direkt in der Klasse erfolgt:

    Geht nicht:

    class A {
    public: 
    	A() {
    
    	}
    
    	static const int m_base, m_offset;
    
    	enum Adressen { Eins = m_base, Zwei = m_base + m_offset, Drei = m_base + 2 * m_offset };
    
    };
    
    const int A::m_base = 0;
    const int A::m_offset = 20;
    

    Geht:

    class A {
    public: 
    	A() {
    
    	}
    
    	static const int m_base = 0, m_offset = 20;
    
    	enum Adressen { Eins = m_base, Zwei = m_base + m_offset, Drei = m_base + 2 * m_offset };
    
    };
    

    Was ist denn die Begründung dafür?!


  • Mod

    Aufzaehlung schrieb:

    Wie komme ich an die Standardefinitionen? Dann kann ich sowas auch mal selber nachschlagen. Kostet der?

    Ja, der Standard kostet ordentlich Geld, aber die letzten Drafts sind jeweils kostenlos und da steht praktisch das gleiche drin:
    C++98:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf
    C++11:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

    Zum Problem: Es geht definitiv nicht mit const int und static int geht auch nur dann, wenn die Initialisierung direkt in der Klasse erfolgt:

    Doch, const geht ganz sicher. Guckst du hier:
    http://ideone.com/wpuQxN
    Wenn du zu Fehlern Fragen hast, dann zeig auch den Code.

    [...]

    Was ist denn die Begründung dafür?!

    Na, weil beim einen der Wert bekannt ist, beim anderen nicht. Der Compiler kann schließlich nicht hellsehen.



  • Bei deiner Variante sind m_Base und m_offset dann allerdings keine Klassenattribute mehr?

    Zu der static-Geschichte: Wieso ist dem Compiler der Wert unbekannt, wenn die Initialisierung außerhalb der Klasse erfolgt?! Er kompiliert doch alles durch?


  • Mod

    Aufzaehlung schrieb:

    Bei deiner Variante sind m_Base und m_offset dann allerdings keine Klassenattribute mehr?

    Ja, wie denn sonst? Als Klassenattribute ist deine Variante mit dem static const. Denk dran, dass const in seiner Bedeutung je nach Kontext überladen ist:

    class foo{
     const int bar; // Keine Compilezeitkonstante!
    };
    

    Zu der static-Geschichte: Wieso ist dem Compiler der Wert unbekannt, wenn die Initialisierung außerhalb der Klasse erfolgt?! Er kompiliert doch alles durch?

    Von oben nach unten. Was, wenn die Definition in einer ganz anderen Übersetzungseinheit erfolgen würde?

    (Deine beiden Varianten sind auch technisch ein bisschen unterschiedlich, gerade aus diesem Grund. Im Prinzip gehen die Regeln des Compiliervorgangs aus den Regeln des Standards hervor. Aber eine gute Faustregel ist, dass der Compiler einmal von oben nach unten durchgeht. Damit kann man sehr vieles an C und C++ erklären. [An die Klugscheißer: Ja, mir sind die Ausnahmen bekannt, wo das nicht so einfach ist. Die sind hier nur wenig relevant.])


  • Mod

    SeppJ schrieb:

    C++11:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

    Eine bessere Wahl ist:
    http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf
    Dieses Dokument ist tatsächlich identisch mit dem Standard mit Ausnahme einiger redaktioneller Korrekturen.


Anmelden zum Antworten