Gibt es einen Unterschied zwischen den folgenden Definitionen?
const double PI = 3.141592653589793;
constexpr double PI = 3.141592653589793;
Wenn nicht, welcher Stil wird in C++ 11 bevorzugt?
Ich glaube, dass es einen Unterschied gibt. Benennen wir sie um, damit wir leichter über sie sprechen können:
const double PI1 = 3.141592653589793;
constexpr double PI2 = 3.141592653589793;
Beide PI1
und PI2
sind konstant, dh Sie können sie nicht ändern. Jedoch nurPI2
ist eine Konstante zur Kompilierungszeit. Es soll zur Kompilierzeit initialisiert werden. PI1
kann zur Kompilier- oder Laufzeit initialisiert werden. Außerdem nurPI2
kann in einem Kontext verwendet werden, der eine Konstante für die Kompilierungszeit erfordert. Zum Beispiel:
constexpr double PI3 = PI1; // error
aber:
constexpr double PI3 = PI2; // ok
und:
static_assert(PI1 == 3.141592653589793, ""); // error
aber:
static_assert(PI2 == 3.141592653589793, ""); // ok
Was solltest du verwenden? Verwenden Sie, was auch immer Ihren Bedürfnissen entspricht. Möchten Sie sicherstellen, dass Sie über eine Kompilierungszeitkonstante verfügen, die in Kontexten verwendet werden kann, in denen eine Kompilierungszeitkonstante erforderlich ist? Möchten Sie es mit einer zur Laufzeit ausgeführten Berechnung initialisieren können? Usw.
Kein Unterschied, aber es ist wichtig, wenn Sie einen Typ haben, der einen Konstruktor hat.
struct S {
constexpr S(int);
};
const S s0(0);
constexpr S s1(1);
s0
ist eine Konstante, die jedoch keine Initialisierung zur Kompilierungszeit verspricht. s1
ist als constexpr
markiert, daher ist es eine Konstante. Da der Konstruktor von S
auch als constexpr
markiert ist, wird er zur Kompilierungszeit initialisiert.
In den meisten Fällen ist dies wichtig, wenn die Initialisierung zur Laufzeit zeitaufwändig ist und Sie diese Arbeit auf den Compiler übertragen möchten, wo dies ebenfalls zeitaufwändig ist, aber die Ausführungszeit des kompilierten Programms nicht verlangsamt
constexpr gibt einen Wert an, der konstant ist und während der Kompilierung bekannt ist.
const gibt einen Wert an, der nur konstant ist; Es ist nicht zwingend erforderlich, dies während der Kompilierung zu wissen.
int sz;
constexpr auto arraySize1 = sz; // error! sz's value unknown at compilation
std::array<int, sz> data1; // error! same problem
constexpr auto arraySize2 = 10; // fine, 10 is a compile-time constant
std::array<int, arraySize2> data2; // fine, arraySize2 is constexpr
Beachten Sie, dass const nicht die gleiche Garantie bietet wie constexpr, da const-Objekte nicht mit Werten initialisiert werden müssen, die beim Kompilieren bekannt sind.
int sz;
const auto arraySize = sz; // fine, arraySize is const copy of sz
std::array<int, arraySize> data; // error! arraySize's value unknown at compilation
Alle constexpr-Objekte sind const, aber nicht alle const-Objekte sind constexpr.
Wenn Compiler sicherstellen sollen, dass eine Variable einen Wert hat, der in Kontexten verwendet werden kann, in denen Konstanten zur Kompilierungszeit erforderlich sind, müssen Sie nach constexpr und nicht nach const greifen.
Einer constexpr symbolischen Konstante muss ein Wert zugewiesen werden, der zur Kompilierungszeit bekannt ist. Zum Beispiel:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
constexpr int c2 = n+7; // Error: we don’t know the value of c2
// ...
}
Um Fälle zu behandeln, in denen der Wert einer „Variablen“ mit einem Wert initialisiert wird, der zur Kompilierungszeit nicht bekannt ist, sich aber nach der Initialisierung nie ändert, bietet C++ eine zweite Form der Konstante (a const) an. Zum Beispiel:
constexpr int max = 100;
void use(int n)
{
constexpr int c1 = max+7; // OK: c1 is 107
const int c2 = n+7; // OK, but don’t try to change the value of c2
// ...
c2 = 7; // error: c2 is a const
}
Solche “const Variablen” sind aus zwei Gründen sehr verbreitet:
Referenz: "Programmieren: Grundlagen und Übung mit C++" von Stroustrup