constexpr und consteval
Teil des Abschnitts Objektorientierte Programmierung der C++-Journey von Coddy — Lektion 87 von 104.
C++ ermöglicht es, Berechnungen zur Kompilierzeit statt zur Laufzeit durchzuführen, was die Performance erheblich verbessern kann. Das Schlüsselwort constexpr (C++11) und das Schlüsselwort consteval (C++20) geben Ihnen die Kontrolle darüber, wann Ausdrücke ausgewertet werden.
Eine constexpr-Funktion kann zur Kompilierzeit ausgewertet werden, wenn sie konstante Argumente erhält, aber sie kann auch zur Laufzeit mit nicht-konstanten Eingaben ausgeführt werden:
#include <iostream>
constexpr int square(int n) {
return n * n;
}
int main() {
constexpr int compileTime = square(5); // Zur Kompilierzeit ausgewertet
int x = 7;
int runtime = square(x); // Zur Laufzeit ausgewertet
std::cout << compileTime << "\n"; // 25
std::cout << runtime << "\n"; // 49
}Wenn Sie eine Auswertung zur Kompilierzeit garantieren müssen, verwenden Sie consteval. Eine consteval-Funktion muss eine Konstante erzeugen – sie mit Laufzeitwerten aufzurufen, ist ein Kompilierfehler:
consteval int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n - 1);
}
int main() {
constexpr int result = factorial(5); // OK: 120 zur Kompilierzeit berechnet
// int x = 5;
// int bad = factorial(x); // FEHLER: x ist keine Konstante
}Sie können constexpr auch mit Variablen und sogar Klassenkonstruktoren verwenden, was es ermöglicht, ganze Objekte zur Kompilierzeit zu erstellen. Dies ist besonders nützlich für Lookup-Tabellen, Konfigurationswerte oder alle Daten, die sich während der Programmausführung nicht ändern.
Aufgabe
EinfachSie werden Ihren Code in drei Dateien organisieren:
MathUtils.h: Definieren Sie Ihre mathematischen Funktionen für die Kompilierzeit.Erstellen Sie die folgenden Funktionen:
cube— eineconstexpr-Funktion, die einintentgegennimmt und dessen Kubikzahl (n * n * n) zurückgibt.triangularNumber— eineconstexpr-Funktion, die die n-te Dreieckszahl mit der Formel n * (n + 1) / 2 berechnet. In dieser Aufgabe rufen wir sie nur im Kompilierzeit-Kontext auf und speichern ihr Ergebnis in einerconstexpr-Variablen.sumOfSquares— eineconstexpr-Funktion, die zwei Ganzzahlen entgegennimmt und die Summe ihrer Quadrate (a*a + b*b) zurückgibt.
Config.h: Erstellen Sie eine Konfigurationsstruktur unter Verwendung von Kompilierzeit-Konstanten.Definieren Sie ein
Config-Struct mit einemconstexpr-Konstruktor, der drei Ganzzahlen entgegennimmt:width,heightunddepth. Speichern Sie diese als öffentliche Member. Fügen Sie außerdem eineconstexpr-Methode namensvolume()hinzu, die width * height * depth zurückgibt.Erstellen Sie unterhalb des Structs eine globale
constexpr-Konstante namensDEFAULT_CONFIG, die mit den Werten 10, 20 und 5 initialisiert wird.main.cpp: Lesen Sie zwei Ganzzahlen von der Eingabe ein, die Laufzeitwerte darstellen.Demonstrieren Sie zunächst die Auswertung zur Kompilierzeit, indem Sie
constexpr-Variablen erstellen:- Speichern Sie
cube(4)in einer constexpr-Variablen und geben Sie aus:Cube of 4: [value] - Speichern Sie
triangularNumber(10)in einer constexpr-Variablen und geben Sie aus:10th triangular number: [value] - Geben Sie das Volumen der Standardkonfiguration aus:
Default volume: [value]
Demonstrieren Sie dann, dass
constexpr-Funktionen auch zur Laufzeit funktionieren können, indem Sie Ihre beiden Eingabewerte verwenden:- Rufen Sie
cube()mit der ersten Eingabe auf und geben Sie aus:Cube of [input]: [result] - Rufen Sie
sumOfSquares()mit beiden Eingaben auf und geben Sie aus:Sum of squares: [result]
- Speichern Sie
Zum Beispiel mit den Eingaben 3 und 4:
Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 3: 27
Sum of squares: 25Mit den Eingaben 5 und 12:
Cube of 4: 64
10th triangular number: 55
Default volume: 1000
Cube of 5: 125
Sum of squares: 169Probier es selbst
#include <iostream>
#include "MathUtils.h"
#include "Config.h"
using namespace std;
int main() {
// Zwei Ganzzahlen von der Eingabe lesen
int input1, input2;
cin >> input1;
cin >> input2;
// TODO: Auswertung zur Kompilierzeit demonstrieren
// Erstelle eine constexpr-Variable, die cube(4) speichert, und gib aus: "Cube of 4: [value]"
// TODO: Erstelle eine constexpr-Variable, die triangularNumber(10) speichert
// und gib aus: "10th triangular number: [value]"
// TODO: Gib das Standardvolumen der Konfiguration aus: "Default volume: [value]"
// TODO: Demonstriere die Laufzeitnutzung von constexpr-Funktionen
// Rufe cube() mit input1 auf und gib aus: "Cube of [input1]: [result]"
// TODO: Rufe sumOfSquares() mit beiden Eingaben auf
// und gib aus: "Sum of squares: [result]"
return 0;
}Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienC++ Build & KompilierungHeader-Dateien & QuelldateienNamensräume & GültigkeitsbereicheEinführung in OOP in C++Klassen vs. ObjekteDer 'this'-PointerMethoden (Elementfunktionen)Attribute (Datenelemente)Grundlagen zu Ctors & DtorsRückblick - Einfacher Taschenrechner4Klasseneigenschaften
Instanz- vs. statische MemberGetter und SetterConst-MemberfunktionenMutable-SchlüsselwortStatische Methoden und VariablenFriend-Funktionen & KlassenZusammenfassung - Bankkonto-Manager7Vererbung
Grundlagen der VererbungZugriffsstufen bei VererbungAufrufreihenfolge von Ctor & DtorÜberschreiben von MethodenVirtuelle Funktionen & VTableMehrfachvererbungVirtuelle VererbungRückblick - Mitarbeiter-Hierarchie2Speicherverwaltung
Stack vs. Heap SpeicherZeiger und ReferenzenDynamischer Speicher (new/delete)Smart Pointers in C++RAII in C++Rückblick – Dynamischer Array-Manager5Kapselung
Zugriffsspezifizierer in C++Zugriffsspezifizierer im DetailInformation HidingStruct vs. ClassVerschachtelte & innere KlassenRückblick - Studentenverwaltungssystem8Polymorphie
Kompilierzeit- vs. Laufzeit-PolymorphieFunktionsüberladungVirtuelle Funktionen – WiederholungRein virtuelle FunktionenAbstrakte KlassenInterface-Design in C++Dynamic Casting & RTTIZusammenfassung – Formen-Rechner3Konstruktoren & Destruktoren
StandardkonstruktorParametrisierter KonstruktorKopierkonstruktorVerschiebekonstruktorKonstruktor-InitialisierungslistenDelegierende KonstruktorenDestruktoren im DetailRule of Three / Five / ZeroZusammenfassung - String-Klasse6Operatorüberladung
Einführung in die OperatorüberladungArithmetische OperatorüberladungVergleichsoperatorüberladungStream-OperatorenZuweisungsoperatorüberladungÜberladen der [] und () OperatorenTypumwandlungsoperatorenRückblick - Matrix-Klasse9Templates
FunktionstemplatesKlassentemplatesTemplate-SpezialisierungVariadische TemplatesSFINAE & Type Traits GrundlagenRückblick - Generische Container12Moderne C++ Features
Move-Semantik & RvaluesPerfect ForwardingLambda-Ausdrücke im Detailstd::function & std::bindconstexpr und constevalStructured Bindingsoptional, variant, any