Namespaces
Variants

Enumeration declaration

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Eine Enumeration ist ein eigener Typ, dessen Wert auf einen Wertebereich beschränkt ist (siehe unten für Details), der mehrere explizit benannte Konstanten (" Enumeratoren ") enthalten kann.

Die Werte der Konstanten sind Werte eines ganzzahligen Typs, der als der zugrundeliegende Typ der Aufzählung bekannt ist. Eine Aufzählung hat dieselbe Größe , Wertdarstellung und Ausrichtungsanforderungen wie ihr zugrundeliegender Typ. Darüber hinaus hat jeder Wert einer Aufzählung dieselbe Darstellung wie der entsprechende Wert des zugrundeliegenden Typs.

Eine Aufzählung wird mit der folgenden Syntax (neu)deklariert:

enum-key attr  (optional) enum-head-name  (optional) enum-base  (optional)
{ enumerator-list  (optional) }
(1)
enum-key attr  (optional) enum-head-name  (optional) enum-base  (optional)
{ enumerator-list , }
(2)
enum-key attr  (optional) enum-head-name enum-base  (optional) ; (3) (seit C++11)
1) enum-specifier , der in der decl-specifier-seq der Deklaration -Syntax erscheint: definiert den Aufzählungstyp und seine Enumeratoren.
2) Ein abschließendes Komma kann der enumerator-list folgen.
3) Deklaration eines opaken Enums: definiert den Enumerationstyp, aber nicht seine Enumeratoren: nach dieser Deklaration ist der Typ ein vollständiger Typ und seine Größe ist bekannt.
enum-key -

enum

(bis C++11)

eines von enum , enum class oder enum struct

(seit C++11)
attr - (seit C++11) optionale Folge beliebig vieler Attribute
enum-head-name -

der Name der deklarierten Enumeration, kann weggelassen werden.

(bis C++11)

der Name der deklarierten Enumeration, optional vorangestellt von einem nested-name-specifier : Sequenz von Namen und Bereichsauflösungsoperatoren :: , endend mit dem Bereichsauflösungsoperator. Kann nur bei unbegrenzten nicht-opaken Enumerationsdeklarationen weggelassen werden.
nested-name-specifier darf nur erscheinen, wenn der Enumerationsname vorhanden ist und diese Deklaration eine Neudeklaration ist. Für opake Enumerationsdeklarationen kann nested-name-specifier nur vor dem Namen der Enumeration in expliziten Spezialisierungsdeklarationen erscheinen.
Wenn nested-name-specifier vorhanden ist, darf sich der enum-specifier nicht auf eine Enumeration beziehen, die lediglich geerbt oder durch eine using -Deklaration eingeführt wurde, und der enum-specifier kann nur in einem Namespace erscheinen, der die vorherige Deklaration umschließt. In solchen Fällen darf nested-name-specifier nicht mit einem decltype -Spezifizierer beginnen.

(seit C++11)
enum-base - (seit C++11) Doppelpunkt ( : ), gefolgt von einem type-specifier-seq , der einen integralen Typ benennt (falls er cv-qualifiziert ist, werden Qualifikationen ignoriert), der als fester zugrundeliegender Typ für diesen Enumerationstyp dient
enumerator-list - kommagetrennte Liste von Enumeratordefinitionen, von denen jede entweder einfach ein eindeutiger identifier ist, der zum Namen des Enumerators wird, oder ein eindeutiger Bezeichner mit einem konstanten Ausdruck: identifier = constant-expression . In beiden Fällen kann der identifier direkt von einer optionalen Attributspezifizierer-Sequenz gefolgt werden. (seit C++17)

Es gibt zwei verschiedene Arten von Aufzählungen: unbegrenzte Aufzählung (deklariert mit dem enum-key enum ) und begrenzte Aufzählung (deklariert mit dem enum-key enum class oder enum struct ).

Inhaltsverzeichnis

Unbegrenzte Aufzählungen

enum name  (optional) { enumerator = constant-expression , enumerator = constant-expression , ... } (1)
enum name  (optional) : type { enumerator = constant-expression , enumerator = constant-expression , ... } (2) (seit C++11)
enum name : type ; (3) (seit C++11)
1) Deklariert einen unbegrenzten Aufzählungstyp, dessen zugrundeliegender Typ nicht festgelegt ist (in diesem Fall ist der zugrundeliegende Typ ein implementierungsdefinierter Ganzzahltyp, der alle Aufzählerwerte darstellen kann; dieser Typ ist nicht größer als int , es sei denn, der Wert eines Aufzählers passt nicht in einen int oder unsigned int . Wenn die enumerator-list leer ist, ist der zugrundeliegende Typ so, als ob die Aufzählung einen einzelnen Aufzähler mit dem Wert 0 hätte. Wenn kein Ganzzahltyp alle Aufzählerwerte darstellen kann, ist die Aufzählung fehlerhaft).
2) Deklariert einen unbegrenzten Aufzählungstyp, dessen zugrundeliegender Typ festgelegt ist.
3) Eine undurchsichtige Enum-Deklaration für eine unbegrenzte Enumeration muss den Namen und den zugrunde liegenden Typ angeben.

Jeder Enumerator wird zu einer benannten Konstante des Enumerationstyps (d.h. name ), sichtbar im umschließenden Gültigkeitsbereich, und kann verwendet werden, wann immer Konstanten erforderlich sind.

enum Color { red, green, blue };
Color r = red;
switch(r)
{
    case red  : std::cout << "rot\n";    break;
    case green: std::cout << "grün\n";  break;
    case blue : std::cout << "blau\n";   break;
}

Jeder Enumerator ist mit einem Wert des zugrundeliegenden Typs assoziiert. Wenn = in einer enumerator-list angegeben werden, werden die Werte der Enumeratoren durch die zugehörigen constant-expression s definiert. Wenn der erste Enumerator kein = besitzt, ist der assoziierte Wert null. Für jeden anderen Enumerator, dessen Definition kein = aufweist, ist der assoziierte Wert der Wert des vorherigen Enumerators plus eins.

enum Foo { a, b, c = 10, d, e = 1, f, g = f + c };
//a = 0, b = 1, c = 10, d = 11, e = 1, f = 2, g = 12

Der Name einer unbegrenzten Enumeration kann weggelassen werden: Eine solche Deklaration führt nur die Enumeratoren in den einschließenden Gültigkeitsbereich ein:

enum { a, b, c = 0, d = a + 2 }; // definiert a = 0, b = 1, c = 0, d = 2

Wenn eine unbegrenzte Aufzählung ein Klassenmitglied ist, können ihre Enumeratoren mit den Klassenmitglied-Zugriffsoperatoren . und -> zugegriffen werden:

struct X
{
    enum direction { left = 'l', right = 'r' };
};
X x;
X* p = &x;
int a = X::direction::left; // nur in C++11 und später erlaubt
int b = X::left;
int c = x.left;
int d = p->left;

In den Deklarationsspezifizierern einer Memberdeklaration wird die Sequenz

enum enum-head-name :

immer als Teil einer Aufzählungsdeklaration geparst:

struct S
{
    enum E1 : int {};
    enum E1 : int {}; // Fehler: Neudeklaration der Aufzählung,
                      // NICHT geparst als Bitfeld der Länge Null vom Typ enum E1
};
enum E2 { e1 };
void f()
{
    false ? new enum E2 : int(); // OK: 'int' wird NICHT als zugrundeliegender Typ geparst
}
(seit C++11)

Aufzählungsname für Verknüpfungszwecke

Eine unbenannte Enumeration, die keinen typedef-Namen für Verknüpfungszwecke besitzt und einen Enumerator hat, wird für Verknüpfungszwecke durch ihren zugrundeliegenden Typ und ihren ersten Enumerator bezeichnet; eine solche Enumeration wird als einen Enumerator als Namen für Verknüpfungszwecke besitzend bezeichnet.

Bereichsbezogene Aufzählungen

enum struct|class name { enumerator = constant-expression , enumerator = constant-expression , ... } (1)
enum struct|class name : type { enumerator = constant-expression , enumerator = constant-expression , ... } (2)
enum struct|class name ; (3)
enum struct|class name : type ; (4)
1) deklariert einen Bereichs-Aufzählungstyp, dessen zugrundeliegender Typ int ist (die Schlüsselwörter class und struct sind exakt äquivalent)
2) deklariert einen Bereichs-Aufzählungstyp, dessen zugrundeliegender Typ type ist
3) opake Enum-Deklaration für eine Bereichs-Aufzählung, deren zugrundeliegender Typ int ist
4) opake Enum-Deklaration für eine Bereichs-Aufzählung, deren zugrundeliegender Typ type ist

Jeder enumerator wird zu einer benannten Konstante des Aufzählungstyps (d.h. name ), die innerhalb des Gültigkeitsbereichs der Aufzählung enthalten ist und mit dem Bereichsauflösungsoperator zugänglich ist. Es gibt keine impliziten Konvertierungen von den Werten eines Bereichs-Aufzählers zu integralen Typen, obwohl static_cast verwendet werden kann, um den numerischen Wert des Aufzählers zu erhalten.

#include <iostream>
int main()
{
    enum class Color { red, green = 20, blue };
    Color r = Color::blue;
    switch(r)
    {
        case Color::red  : std::cout << "red\n";   break;
        case Color::green: std::cout << "green\n"; break;
        case Color::blue : std::cout << "blue\n";  break;
    }
    // int n = r; // Fehler: keine implizite Konvertierung von Bereichs-Enum zu int
    int n = static_cast<int>(r); // OK, n = 21
    std::cout << n << '\n'; // gibt 21 aus
}
(seit C++11)

Eine Enumeration kann ohne Cast von einem Integer initialisiert werden, unter Verwendung von Listeninitialisierung , wenn alle folgenden Bedingungen erfüllt sind:

  • Die Initialisierung ist direkte Listeninitialisierung.
  • Die Initialisierungsliste hat nur ein einzelnes Element.
  • Die Enumeration ist entweder scoped oder unscoped mit festgelegtem zugrundeliegenden Typ.
  • Die Konvertierung ist nicht verengend.

Dies ermöglicht die Einführung neuer Integertypen (z.B. SafeInt ), die die gleichen bestehenden Aufrufkonventionen wie ihre zugrundeliegenden Integertypen genießen, selbst auf ABIs, die das Übergeben/Zurückgeben von Strukturen als Wert benachteiligen.

enum byte : unsigned char {}; // byte is a new integer type; see also std::byte (C++17)
byte b{42};        // OK as of C++17 (direct-list-initialization)
byte c = {42};     // error
byte d = byte{42}; // OK as of C++17; same value as b
byte e{-1};        // error
struct A { byte b; };
A a1 = {{42}};     // error (copy-list-initialization of a constructor parameter)
A a2 = {byte{42}}; // OK as of C++17
void f(byte);
f({42}); // error (copy-list-initialization of a function parameter)
enum class Handle : std::uint32_t { Invalid = 0 };
Handle h{42}; // OK as of C++17
(seit C++17)


using enum Deklaration

using enum using-enum-declarator ; (seit C++20)
Deklarator - ein (möglicherweise qualifizierter) Bezeichner oder einfache Template-Bezeichner


Deklarator muss einen nicht- abhängigen Aufzählungstyp benennen. Die Aufzählungsdeklarationen werden durch typbasierte gewöhnliche qualifizierte oder unqualifizierte Suche gefunden, abhängig davon, ob Deklarator qualifiziert ist.

enum E { x };
void f()
{
    int E;
    using enum E; // OK
}
using F = E;
using enum F; // OK
template<class T>
using EE = T;
void g()
{
    using enum EE<E>; // OK
}

Eine using enum -Deklaration führt die Aufzählernamen der benannten Aufzählung ein, als ob durch eine using -Deklaration für jeden Aufzähler. Im Klassenbereich fügt eine using enum -Deklaration die Aufzähler der benannten Aufzählung als Mitglieder zum Bereich hinzu, wodurch sie für die Mitgliedersuche zugänglich werden.

enum class fruit { orange, apple };
struct S
{
    using enum fruit; // OK: führt orange und apple in S ein
};
void f()
{
    S s;
    s.orange;  // OK: benennt fruit::orange
    S::orange; // OK: benennt fruit::orange
}

Zwei using enum -Deklarationen, die zwei Aufzähler mit demselben Namen einführen, stehen im Konflikt.

enum class fruit { orange, apple };
enum class color { red, orange };
void f()
{
    using enum fruit;    // OK
    // using enum color; // Fehler: color::orange und fruit::orange stehen im Konflikt
}
(seit C++20)

Hinweise

Werte von Aufzählungstypen ohne Gültigkeitsbereich können zu integralen Typen heraufgestuft oder konvertiert werden:

enum color { red, yellow, green = 20, blue };
color col = red;
int n = blue; // n == 21

Werte von Integer-, Gleitkomma- und Aufzählungstypen können durch Verwendung von static_cast in jeden Aufzählungstyp konvertiert werden. Beachten Sie, dass der Wert nach einer solchen Konvertierung nicht notwendigerweise einem der für die Aufzählung definierten benannten Enumeratoren entsprechen muss:

enum access_t { read = 1, write = 2, exec = 4 }; // Enumeratoren: 1, 2, 4 Bereich: 0..7
access_t rwe = static_cast<access_t>(7);
assert((rwe & read) && (rwe & write) && (rwe & exec));
access_t x = static_cast<access_t>(8.0); // Undefiniertes Verhalten seit CWG 1766
access_t y = static_cast<access_t>(8);   // Undefiniertes Verhalten seit CWG 1766
enum foo { a = 0, b = UINT_MAX }; // Bereich: [0, UINT_MAX]
foo x = foo(-1); // Undefiniertes Verhalten seit CWG 1766,
                 // selbst wenn der zugrundeliegende Typ von foo unsigned int ist
Feature-Test-Makro Wert Std Feature
__cpp_enumerator_attributes 201411L (C++17) Attribute für Enumeratoren
__cpp_using_enum 201907L (C++20) using enum

Schlüsselwörter

enum , struct , class , using

Beispiel

#include <cstdint>
#include <iostream>
// Enumeration, die 16 Bits belegt
enum smallenum: std::int16_t
{
    a,
    b,
    c
};
// Farbe kann rot (Wert 0), gelb (Wert 1), grün (Wert 20) oder blau (Wert 21) sein
enum color
{
    red,
    yellow,
    green = 20,
    blue
};
// Höhe kann altitude::high oder altitude::low sein
enum class altitude: char
{
    high = 'h',
    low = 'l', // Nachgestelltes Komma nur erlaubt nach CWG 518
}; 
// Die Konstante d ist 0, die Konstante e ist 1, die Konstante f ist 3
enum
{
    d,
    e,
    f = e + 2
};
// Aufzählungstypen (sowohl scoped als auch unscoped) können überladene Operatoren haben
std::ostream& operator<<(std::ostream& os, color c)
{
    switch(c)
    {
        case red   : os << "red";    break;
        case yellow: os << "yellow"; break;
        case green : os << "green";  break;
        case blue  : os << "blue";   break;
        default    : os.setstate(std::ios_base::failbit);
    }
    return os;
}
std::ostream& operator<<(std::ostream& os, altitude al)
{
    return os << static_cast<char>(al);
}
// Der scoped enum (C++11) kann in früheren C++-Revisionen teilweise emuliert werden:
enum struct E11 { x, y }; // seit C++11
struct E98 { enum { x, y }; }; // OK in pre-C++11
namespace N98 { enum { x, y }; } // OK in pre-C++11
struct S98 { static const int x = 0, y = 1; }; // OK in pre-C++11
void emu()
{
    std::cout << (static_cast<int>(E11::y) + E98::y + N98::y + S98::y) << '\n'; // 4
}
namespace cxx20
{
    enum class long_long_long_name { x, y };
    void using_enum_demo()
    {
        std::cout << "C++20 `using enum`: __cpp_using_enum == ";
        switch (auto rnd = []{return long_long_long_name::x;}; rnd())
        {
#if defined(__cpp_using_enum)
            using enum long_long_long_name;
            case x: std::cout << __cpp_using_enum << "; x\n"; break;
            case y: std::cout << __cpp_using_enum << "; y\n"; break;
#else
            case long_long_long_name::x: std::cout << "?; x\n"; break;
            case long_long_long_name::y: std::cout << "?; y\n"; break;
#endif
        }
    }
}
int main()
{
    color col = red;
    altitude a;
    a = altitude::low;
    std::cout << "col = " << col << '\n'
              << "a = "   << a   << '\n'
              << "f = "   << f   << '\n';
    cxx20::using_enum_demo();
}

Mögliche Ausgabe:

col = rot
a = l
f = 3
C++20 `using enum`: __cpp_using_enum == 201907; x

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 377 C++98 das Verhalten war nicht spezifiziert, wenn kein integraler
Typ alle Enumeratorwerte darstellen kann
die Enumeration ist in diesem Fall
fehlerhaft
CWG 518 C++98 ein nachgestelltes Komma war nach der Enumeratorliste nicht erlaubt erlaubt
CWG 1514 C++11 eine Neudefinition einer Enumeration mit festgelegtem zugrunde liegenden Typ
konnte als Bitfeld in einer Klassenmember-Deklaration geparst werden
immer als Neudefinition geparst
CWG 1638 C++11 Grammatik der opaken Enumerationsdeklaration
verbot die Verwendung für Template-Spezialisierungen
Nested-Name-Specifier
erlaubt
CWG 1766 C++98 das Konvertieren eines Wertes außerhalb des Bereichs in eine Enumeration
ohne festgelegten zugrunde liegenden Typ hatte ein nicht spezifiziertes Ergebnis
das Verhalten ist undefiniert
CWG 1966 C++11 die Lösung von CWG Issue 1514 machte den :
eines bedingten Ausdrucks Teil von enum-base
wende die Lösung nur auf
Member-Deklarationsspezifizierer an
CWG 2156 C++11 Enum-Definitionen konnten Enumerationstypen
durch using-Deklarationen definieren
verboten
CWG 2157 C++11 die Lösung von CWG Issue 1966 deckte
keine qualifizierten Enumerationsnamen ab
abgedeckt
CWG 2530 C++98 eine Enumeratorliste konnte mehrere
Enumeratoren mit demselben Bezeichner enthalten
verboten
CWG 2590 C++98 die Größe, Wertdarstellung und Ausrichtungsanforderungen
einer Enumeration hingen nicht von ihrem zugrunde liegenden Typ ab
alle sind identisch mit
denen des zugrunde liegenden Typs
CWG 2621 C++20 die in
using enum Deklarationen verwendete Enumerationsnamensuche war unklar
klargestellt
CWG 2877 C++20 die in
using enum Deklarationen verwendete Enumerationsnamensuche war nicht typ-only
zu typ-only gemacht

Referenzen

  • C++23-Standard (ISO/IEC 14882:2024):
  • 9.7.1 Enumeration declarations [dcl.enum]
  • C++20-Standard (ISO/IEC 14882:2020):
  • 9.7.1 Aufzählungsdeklarationen [dcl.enum]
  • C++17-Standard (ISO/IEC 14882:2017):
  • 10.2 Aufzählungsdeklarationen [dcl.enum]
  • C++14-Standard (ISO/IEC 14882:2014):
  • 7.2 Aufzählungsdeklarationen [dcl.enum]
  • C++11-Standard (ISO/IEC 14882:2011):
  • 7.2 Aufzählungsdeklarationen [dcl.enum]
  • C++03-Standard (ISO/IEC 14882:2003):
  • 7.2 Aufzählungsdeklarationen [dcl.enum]
  • C++98-Standard (ISO/IEC 14882:1998):
  • 7.2 Aufzählungsdeklarationen [dcl.enum]

Siehe auch

(C++11)
prüft, ob ein Typ ein Aufzählungstyp ist
(Klassentemplate)
prüft, ob ein Typ ein scoped enumeration type ist
(Klassentemplate)
ermittelt den zugrundeliegenden Integer-Typ für einen gegebenen Aufzählungstyp
(Klassentemplate)
konvertiert eine Aufzählung in ihren zugrundeliegenden Typ
(Funktionstemplate)
C-Dokumentation für Aufzählungen