Quoting 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 type is defined in [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.
Scalar type is in paragraph 9:
Arithmetic types (3.9.1), enumeration types, pointer types, pointer to member types (3.9.2), std::nullptr_t
, and cv-qualified versions of these types (3.9.3) are collectively called scalar types.
int
is arithmetic, so volatile int
is a scalar type and hence a literal type. constexpr volatile int i = 5;
is thus a well-formed declaration.
Interestingly, an expression that evaluates i
cannot be a core-constant-expression since it applies an lvalue-to-rvalue conversion to a glvalue of volatile type ([expr.const]/2). Consequently, expressions that evaluate i
are neither integral constant expressions nor constant expressions. I'm not sure that the constexpr
in that declaration has any effect beyond making i
implicitly const
, and (nod to @T.C.) requiring its initializer to be a constant expression.
I've reported this as GCC bug 65327, we'll see what the GCC folks have to say.
2015-03-16 Update: Bug has been fixed for GCC 5.
constexpr
andconst
are not the same – Horalvolatile
doesn't mean anything has a tendency to change. it just means that the memory access can have side effects, and the compiler should therefore treat it as I/O. It can very well be necessary to usevolatile
on a system even when the value is guaranteed to stay constant. – Handknitconstexpr
impliesconst
. – Grumpyconstexpr std::string
object. – HoralisRunning
boolean that can be altered from another thread. Marking itvolatile
ensures the compiler will not make a dumb decision regarding its value in other stages of the code. – Shouldersconst volatile
outside of embedded programming? – Shouldersvolatile
does not provide any synchronization. It may work under right cirumstances (suitable CPU etc), but it is not in any way guaranteed to work, so use atomics for that kind of inter-thread flag, unless you want to intentionally write bad code. You useconst volatile
when you want to only readvolatile
variable, and want a compiler error if you try to write to it (whatever changes the value would then need to somehow work around constness, of course). – Pylosconst volatile
might make sense for a read-only memory map of a file that another process is concurrently modifying, or read-only memory-mapped registers of a hardware device. – Floozy