Video: BOB 2016 - Gregor Große-Bölting - Elm im produktiven Einsatz 2024
Beim Programmieren dreht sich alles um Lesbarkeit. Es ist schwierig (eigentlich unmöglich), ein Programm zu schreiben und zu pflegen, das man nicht lesen kann. Ein Teil des Lesens einer Quellcode-Auflistung ist das Verstehen, was die in dem Programm verwendeten Zahlen darstellen. Die einfachste Hilfe, die C ++ bietet, ist die allgegenwärtige #define, wie im folgenden oft zitierten Beispiel:
#define PI 3. 141592653589793
Diese Lösung ist für einzelne Werte in Ordnung, obwohl sie unter der Tatsache leidet, dass die #define-Mechanismus ist (streng genommen) kein Teil von C / C ++, da der Präprozessor vor dem Compiler läuft. Als Antwort darauf hat C ++ 2011 ein Constant Expression Konstrukt eingeführt:
constexpr long double PI = 3. 141592653589793;
Das Schlüsselwort constexpr bringt Konstanten in das C ++ - Zelt. Dieser PI hat wie andere C ++ - Variablen einen echten Typ. C ++ kann Fehlermeldungen mit PI erzeugen, die viel sinnvoller sind als solche mit 3. 14159.
Konstante Ausdrücke eignen sich gut für einzelne konstante Werte, aber oft repräsentieren Konstanten Mengen von Dingen anstelle von natürlichen Konstanten, wie im folgenden Beispiel:
#define DC_OR_TERRITORY 0 #define ALABAMA 1 #define ALASKA 2 #define ARKANSAS 3 // … und so weiter …
Vermutlich werden diese Konstanten verwendet, um die Zustände zu identifizieren. ein Index in ein Array von Zustandsobjekten oder irgendwo als Wert in einer Datenbank.
C ++ verfügt seit langem über einen verbesserten Mechanismus zur Definition dieser Konstantentypen - die Enumeration:
enum STATE {DC_OR_TERRITORY, // erhält 0 ALABAMA, // bekommt 1 ALASKA, // bekommt 2 ARKANSAS, // … und bald…};
Das enum-Schlüsselwort führt eine Sequenz von Konstanten ein, die als "Enumeration" bezeichnet wird. In diesem Fall trägt die Enumeration den Namen STATE. Jedem Element dieser Aufzählung wird ein Wert zugewiesen, der bei 0 beginnt und sequentiell um 1 erhöht wird. DC_OR_TERRITORY ist also als 0 definiert, ALABAMA ist als 1 definiert und so weiter. Sie können diese inkrementelle Sequenzierung überschreiben, indem Sie eine Zuweisungsanweisung wie folgt verwenden:
enum ZUSTAND {DC, TERRITORY = 0, ALABAMA, ALASKA, // … und so weiter …};
Diese Version von STATE definiert ein Element DC, das den Wert 0 erhält. Es definiert dann ein neues Element TERRITORY, dem ebenfalls der Wert 0 zugewiesen wird. ALABAMA nimmt wie zuvor mit 1 auf.
In der Praxis kann der Programmierer Enumerationen verwenden, um recht lesbaren Code wie den folgenden zu schreiben:
double taxRate (STATE s) {return taxRatesByState [s];}
Das einzige Problem bei diesem Ansatz ist, dass diese Aufzählung erzeugt keinen neuen Typ (wie Sie vielleicht denken).Tatsächlich ist STATE laut dem Standard nur ein anderer Name für int - und die Konstanten ALABAMA, ALASKA usw. sind alle vom Typ const int.
Der gcc-Compiler stellt tatsächlich eine Enumeration, die auf diese Weise deklariert wurde, ein wenig mehr Autorität bereit, als sie einfach als eine andere Form von int zu bezeichnen. Sie können Funktionen auf Basis eines Enum-Typs tatsächlich überladen:
void fn (STATE s); ungültig fn (int n); fn (ALASKA); // ruft fn (STATE)
auf. Der 2011-Standard ermöglicht es dem Programmierer, mit dem Schlüsselwort enum einen völlig neuen Typ zu erstellen. Da die Ersteller des neuen Standards den vorhandenen Code nicht unterbrechen wollten, erfordert der Standard das Hinzufügen eines zusätzlichen Schlüsselworts, um einen Aufzählungstyp zu definieren, wie im folgenden Beispiel:
Enum-Klasse ZUSTAND {DC, TERRITORY = 0, ALABAMA, ALASKA, // … und so weiter …};
Eine Aufzählungsklasse ist jetzt wie jede andere benutzerdefinierte Klasse ein vollständiger Typ. Das Folgende ist aus zwei Gründen nicht einmal mehr legal:
int s = ALASKA;
Zunächst wird die Konstante ALASKA nur innerhalb des STATE-Namensraums definiert. Daher lautet der Name der Konstante STATE:: ALASKA. Zweitens ist der Typ nicht int, sondern STATE. Sie können einem int keinen Wert vom Typ STATE zuweisen.
STAAT s = ZUSTAND:: ALASKA;
Der Programmierer kann einen STATE in einen int umformatieren, muss dies aber explizit tun - implizite Konvertierungen schneiden ihn nicht mit Aufzählungsklassen ab:
int n = (int) STATE:: ALASKA;
Dieser neue Enum-Typ kann auch auf einem der anderen Zähl-Zahlentypen außer nur int basieren:
Enum-Klasse STATE: char {DC, // … der Rest der Deklaration ist gleich