2015-03-05 5 views
26

Der folgende Ausschnitt arbeitet in Clang 3.5 in Ordnung, aber nicht in GCC 4.9.2:Kann consExpr mit volatilen kombiniert werden?

int main() 
{ 
    constexpr volatile int i = 5; 
} 

mit Fehler:

error: both 'volatile' and 'constexpr' cannot be used here

Wenn ich die Assembly, die Clang erzeugt inspizieren, zeigt es 5 wie erwartet:

movl $5, -4(%rsp) 

In GCC wird constexpr int i = 5 weg optimiert, aber volatile int i = 5 zeigt auch 5 in der Versammlung. volatile const int i = 5 kompiliert in beiden Compilern. Es ist kein fremdes Konzept, dass etwas sowohl flüchtig als auch konstant ist.

Welcher Compiler ist nach den Standards korrekt?

+0

Was ist es, Sie versuchen, auszudrücken? Sie sind im Wesentlichen Gegensätze. Eine Konstante wird sich nie ändern, sobald sie gesetzt ist, aber ein Volatile ist fast garantiert, sich zu ändern (möglicherweise sogar von einem anderen Thread). – TheBuzzSaw

+2

'conetexpr' und' const' sind nicht gleich –

+9

@TheBuzzSaw: 'volatile' bedeutet nicht, dass irgendetwas eine Tendenz zur Veränderung hat. es bedeutet nur, dass der Speicherzugriff Nebenwirkungen haben kann, und der Compiler sollte es daher als I/O behandeln. Es kann sehr gut notwendig sein, "flüchtig" auf einem System zu verwenden, selbst wenn der Wert garantiert konstant bleibt. – Mehrdad

Antwort

23

Ja, das gültig ist, war es defect report 1688: Volatile constexpr variables, die für diese eingereicht wurde, sagte:

There does not appear to be language in the current wording stating that constexpr cannot be applied to a variable of volatile-qualified type. Also, the wording in 5.19 [expr.const] paragraph 2 referring to “a non-volatile object defined with constexpr” might lead one to infer that the combination is permitted but that such a variable cannot appear in a constant expression. What is the intent?

es abgelehnt wie kein Defekt ( NAD), die Antwort und das Grundprinzip war:

The combination is intentionally permitted and could be used in some circumstances to force constant initialization.

da der DR eine solche Variable weist darauf hin, selbst nicht verwendbar in einem konstanten Ausdruck:

constexpr volatile int i = 5;  
constexpr int y = i ;   // Not valid since i is volatile 

Abschnitt [expr.const]/2 umfasst alle Fälle, die einen bedingten Ausdruck kein Kern konstanten Ausdruck einschließlich macht:

an lvalue-to-rvalue conversion (4.1) unless it is applied to

und alle Ausnahme erfordern:

[...]that refers to a non-volatile [...] object [...]

+1

Ich * wusste * da musste eine DR sein, konnte aber keine finden. Gut gemacht. – Casey

17

Zitiert N4140 [dcl.constexpr]/9:

A constexpr specifier used in an object declaration declares the object as const . Such an object shall have literal type and shall be initialized.

Literal-Typ wird in definiert [basic.types]/10:

A type is a literal type if it is:

(10.1) — void ; or

(10.2) — a scalar type; or

(10.3) — a reference type; or

(10.4) — an array of literal type; or

(10.5) — a class type (Clause 9) that has all of the following properties:

(10.5.1) — it has a trivial destructor,

(10.5.2) — it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and

(10.5.3) — all of its non-static data members and base classes are of non-volatile literal types.

skalaren Typ ist in Absatz 9:

int ist arithmetisch, also ist volatile int ein Skalartyp und daher ein Literaltyp. constexpr volatile int i = 5; ist also eine wohlgeformte Erklärung.

Interessanterweise ein Ausdruck, der i kann nicht sein, eine Kern-Konstante-expression da es gilt ein L-Wert-zu-R-Wert Umwandlung in ein glvalue von flüchtigen Typ ([expr.const]/2) auswertet. Folglich sind Ausdrücke, die i auswerten, weder Integralkonstantenausdrücke noch Konstantenausdrücke. Ich bin mir nicht sicher, ob die constexpr in dieser Deklaration irgendeinen Effekt hat, außer i implizit const zu machen, und (nicken zu @T.C.), dass sein Initialisierer ein konstanter Ausdruck sein muss.

Ich habe dies als GCC bug 65327 gemeldet, wir werden sehen, was die GCC Leute zu sagen haben.

2015-03-16 Update: Bug wurde für GCC festgelegt 5.

+0

Das Vorhandensein von "nichtflüchtigen" in (10.5.3) sagt mir, dass es zumindest einigermaßen wahrscheinlich ist, dass der Standard dazu dient, volatile qualifizierte Typen im Allgemeinen auszuschließen und dies zuzulassen, war ein Versehen. – Hurkyl

+4

"Ich bin mir nicht sicher, ob der Contexpr in dieser Deklaration irgendeinen Effekt hat, außer dass ich implizit const gemacht habe." - Es beschränkt den Initialisierer immer noch auf einen konstanten Ausdruck. –

+0

Für was es wert ist, hier ist der [Patch] (http://patchwork.ozlabs.org/patch/173189/), der diesen Fehler einführte. Das Testen auf der Wandbox zeigt, dass der Fehler zwischen 4.5.4 und 4.6.4 eingefügt wurde. – user4637702

Verwandte Themen