it-swarm.com.de

const vs constexpr auf Variablen

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?

254
fredoverflow

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.

293
Howard Hinnant

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

71
Pete Becker

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.

37
Ajay yadav

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:

  1. C++ 98 hatte kein constexpr, daher benutzten die Leute const.
  2. Listeneintrag „Variablen“, die keine konstanten Ausdrücke sind (ihr Wert ist zur Kompilierungszeit nicht bekannt), aber nach der Initialisierung keine Werte ändern, sind an sich sehr nützlich.

Referenz: "Programmieren: Grundlagen und Übung mit C++" von Stroustrup

14
Jnana