2017-12-20 25 views
12

Der Ausdruck b in diesem Code wirdWarum ist dieser Ausdruck kein konstanter Ausdruck?

int main() 
{ 
    constexpr int a = 10; 
    const int &b = a; 
    constexpr int c = b; // here 
    return 0; 
} 

ein Kern konstanter Ausdruck sein, da der Standard sagt (8.20 Absatz 2 [expr.const] in n4700)

Ein Ausdruck e ist a Kernkonstante Ausdruck, es sei denn die Auswertung von e würde einen der folgenden Ausdrücke auswerten:

  • ...

  • ein L-Wert-zu-R-Wert-Umwandlung (7.1), es sei denn, es zu

    • ...

    • angewendet wird ein nichtflüchtiges glvalue, das sich auf bezieht, ein nichtflüchtiges Objekt, das mit constexpr definiert ist, oder das sich auf ein nicht veränderbares Unterobjekt eines solchen O bezieht bject oder

Zuerst wird der Ausdruck b in dem obigen Code ist ein L-Wert (der auch ein glvalue ist), da es eine Referenz ist, wodurch eine Variable ist (8.1.4.1, Absatz 1 [expr.prim.id.unqual]):

der Ausdruck ist ein L-Wert, wenn das Unternehmen eine Funktion ist, variable oder Datenelement und ein prvalue sonst; es ist ein Bitfeld, wenn die Kennung ein Bitfeld (11.5) bezeichnet.

Zweitens ist es die Aufgabe der variable b bezeichnet ist a, und es ist mit constexpr erklärt. Allerdings gcc klagt

./hello.cpp: In function ‘int main()’: 
./hello.cpp:6:20: error: the value of ‘b’ is not usable in a constant expression 
    constexpr int c = b; 
        ^
./hello.cpp:5:13: note: ‘b’ was not declared ‘constexpr’ 
    const int &b = a; 

Soweit ich das beurteilen kann, eine Referenz ist kein Objekt, so dass die obige Kugel schlägt offenbar, dass a wird mit constexpr deklariert werden. Fehle ich etwas? Der Grund, warum ich mit gcc nicht einverstanden bin, ist, dass gcc b als ein Objekt sieht, wodurch es mit constexpr deklariert werden muss. b ist jedoch kein Objekt!

+1

Clang stimmt mit GCC überein. Aber ich denke, ich stimme dir zu, das ist ein Fehler entweder im Standard oder in den Compilern. Beachten Sie auch, dass MSVC den Code akzeptiert. –

Antwort

12

Eine der Regeln für Kern konstantes Ausdrücken ist, dass wir can't evaluate:

eine ID-expression, der ein Variablen oder Datenelementes von Referenztyp bezieht, wenn die Referenz eine vorhergehende Initialisierung und entweder

  • es mit einem konstanten Ausdruck oder
  • seiner Lebenszeit begann in der Evaluation von E initialisiert wird;

b ist ein ID-expression, die mit vorhergehenden Initialisierung einer Variablen des Referenztyp bezieht. Es wird jedoch von a initialisiert. Ist a ein konstanter Ausdruck? Von [expr.const]/6:

A konstanter Ausdruck ist entweder ein glvalue Kern konstanter Ausdruck, der auf eine Entität bezieht, die eine zulässige Folge eines konstanten Ausdrucks ist (wie unten definiert) oder ein prvalue Kern konstanter Ausdruck, dessen Wert erfüllt die folgenden Einschränkungen: [...]

Eine Entität ist ein erlaubtes Ergebnis eines konstanten Ausdrucks, wenn es sich um ein Objekt mit statischer Speicherdauer handelt, das entweder kein temporäres Objekt ist oder ein temporäres Objekt ist, dessen Wert das erfüllt über Einschränkungen, oder es ist eine Funktion.

a ist ein glvalue Kern konstanter Ausdruck (es keine der Beschränkungen in expr.const/2 nicht trifft), aber es ist nicht ein Objekt mit statischer Speicherdauer. Es ist auch keine Funktion.

Daher ist a kein konstanter Ausdruck. Und b, als Ergebnis, wird nicht von einem konstanten Ausdruck initialisiert und kann daher nicht in einem Kernkonstantenausdruck verwendet werden. Und so ist die Initialisierung der c schlecht als nicht konstanter Ausdruck ausgeformt. Deklariere a als static constexpr int, und sowohl gcc als auch clang akzeptieren das Programm.

C++, du magische Bestie.

+2

'b' wird mit einem glvalue initialisiert und **' a' als glvalue ** ist kein konstanter Ausdruck. – cpplearner

+0

@cpplearner Was, warum? – Barry

+0

in der Tat, beachte, dass clang auch "constexpr int const & b = a;" "Referenz auf 'a' ist kein konstanter Ausdruck" ... –

Verwandte Themen