Dieser Code funktioniert:
%Vor% Aber wenn ich int
in float
ändere, bekomme ich einen Fehler:
/tmp/main-272d80.o: In der Funktion
main': main.cpp:(.text+0xe): undefined reference to
Blob :: a '
Warum kann ich nicht constexpr float
auf diese Weise verwenden?
Compiler: Ubuntu-Sprachversion 3.5.0-4ubuntu2 (tags / RELEASE_350 / final)
Getestet auf gcc Version 4.9.1 (Ubuntu 4.9.1-16ubuntu6) und es gab keinen Fehler.
BEARBEITEN:
Es wird kompiliert, wenn ich -O1, -O2, -O3 oder -Os verwende, aber mit -O0
versagtC ++ 11 liest
Eine Variable, deren Name als potenziell ausgewerteter Ausdruck erscheint odr-used es sei denn, es ist ein Objekt, das die Anforderungen für erfüllt erscheint in einem konstanten Ausdruck (5.19) und dem Wert lvalue-to-r Umwandlung (4.1) wird sofort angewendet.
Offensichtlich wird die l-t-r-Umwandlung sofort angewendet, und eine constexpr
-Variable vom Fließkommatyp kann in konstanten Ausdrücken erscheinen wie in [expr.const] / (2.7.1):
Ein
ist ein -Kernkonstantenausdruck , es sei denn, umfasst einen der folgenden als potenziell ausgewerteten Unterausdruck [..]
- eine lvalue-to-rvalue-Konvertierung (4.1), wenn sie nicht angewendet wird
- Ein glvalue des Literaltyps, der sich auf ein nicht-flüchtiges Objekt bezieht, das mit
constexpr
definiert ist, oder das sich auf ein Unterobjekt eines solchen Objekts bezieht Objekt oder
Scheint ein Clang-Bug zu sein.
Interessanterweise, wenn wir stattdessen Blob::a
verwenden, klagt clang
nicht:
Dies sollte nicht wichtig sein, um festzustellen, ob es odr-verwendet wird oder nicht. Das sieht also wie ein clang
Bug aus, den ich auf clang 3.7 reproduzieren kann, ohne nur eine Optimierung zu verwenden. Wir können feststellen, dass dies ein odr Problem ist, da das Hinzufügen einer Out-of-Class-Definition das Problem behebt ( live sehen ) / em>):
Wann müssen Sie ein statisches Mitglied der consExpr-Klasse definieren? Dies wird im Abschnitt 9.4.2
[class.static.data] behandelt, der besagt ( Hervorhebung meiner Zukunft ):
Ein statisches Datenelement des Literaltyps kann in der Klasse deklariert werden Klassendefinition mit dem consExpr-Spezifizierer; Wenn ja, muss in der Deklaration ein "brace-or-equal-initializer" angegeben werden in dem jede Initializerklausel, die ein Zuweisungsausdruck ist, ein konstanter Ausdruck ist. [Anmerkung: In beiden In diesen Fällen kann das Element in konstanten Ausdrücken angezeigt werden. -end note] Das Mitglied soll noch definiert werden in einem Namespace-Bereich, wenn es im Programm odr-used (3.2) ist und die Namespace-Bereichsdefinition nicht enthält einen Initialisierer.
Es erfordert eine Definition, wenn es odr-verwendet wird. Ist es odr-used? Nein ist es nicht. Der ursprüngliche C ++ 11-Wortlaut im Abschnitt 3.2
[basic.def.odr] lautet:
Ein Ausdruck wird möglicherweise ausgewertet, es sei denn, es handelt sich um einen nicht bewerteten Operanden (Abschnitt 5) oder einen Unterausdruck davon. Eine Variable, deren Name als potenziell evaluierter Ausdruck erscheint, wird odr-verwendet, es sei denn ist ein Objekt, das die Anforderungen erfüllt, damit es in einem konstanten Ausdruck erscheint (5.19) und der Wert von lvalue-to-r Konvertierung (4.1) wird sofort angewendet .
a
erfüllt beide Bedingungen, es ist ein konstanter Ausdruck und die lvalue-to-rvalue-Konvertierung wird sofort angewendet. Fehlerbericht 712 hat den für C ++ 11 geltenden Wortlaut geändert da es sich um einen Fehlerbericht handelt und 3.2
jetzt sagt:
Eine Variable x, deren Name als potenziell evaluierter Ausdruck ex angezeigt wird, wird verwendet, es sei denn wird angewendet Lvalue-to-rvalue-Konvertierung (4.1) zu x ergibt einen konstanten Ausdruck (5.19), der kein nicht-triviales aufruft Funktionen und, wenn x ein Objekt ist, ist ex ein Element der Menge möglicher Ergebnisse eines Ausdrucks e, wobei entweder wird die lvalue-to-rvalue-Konvertierung (4.1) auf e angewendet, oder e ist ein Ausdruck mit verworfenem Wert
Das mögliche Ergebnis, das zutrifft, wäre:
Wenn e ein ID-Ausdruck (5.1.1) ist, enthält die Menge nur e.
es ist ein konstanter Ausdruck und die lvalue-to-rvalue-Konvertierung wird angewendet, so dass es nicht odr-used ist.
Tags und Links c++ clang constexpr one-definition-rule