Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can constexpr be combined with volatile?

The following snippet works fine in Clang 3.5 but not in GCC 4.9.2:

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

with error:

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

If I inspect the assembly that Clang generates, it shows 5 as expected:

movl    $5, -4(%rsp) 

In GCC, constexpr int i = 5 is optimized away, but volatile int i = 5 also shows 5 in the assembly. volatile const int i = 5 compiles in both compilers. It's not a foreign concept for something to be both volatile and const at the same time.

Which compiler is correct by the standards?

like image 435
user4637702 Avatar asked Mar 05 '15 17:03

user4637702


People also ask

Can you modify constexpr?

A const int var can be dynamically set to a value at runtime and once it is set to that value, it can no longer be changed. A constexpr int var cannot be dynamically set at runtime, but rather, at compile time. And once it is set to that value, it can no longer be changed.

Does constexpr improve performance?

Understanding constexpr Specifier in C++ constexpr is a feature added in C++ 11. The main idea is a performance improvement of programs by doing computations at compile time rather than run time.

Does constexpr need to be static?

A static constexpr variable has to be set at compilation, because its lifetime is the the whole program. Without the static keyword, the compiler isn't bound to set the value at compilation, and could decide to set it later. So, what does constexpr mean?

Should I use constexpr everywhere?

Yes. I believe putting such const ness is always a good practice wherever you can. For example in your class if a given method is not modifying any member then you always tend to put a const keyword in the end.


2 Answers

Yes, this is valid, there was defect report 1688: Volatile constexpr variables that was filed for this, saying:

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?

it was rejected as not a defect(NAD), the response and rationale was:

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

As the DR points out such a variable is itself not usable in a constant expression:

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

Section [expr.const]/2 includes all the cases that makes a conditional-expression not a core constant expression including:

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

and all the exception require:

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

like image 87
Shafik Yaghmour Avatar answered Oct 04 '22 15:10

Shafik Yaghmour


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.

like image 31
Casey Avatar answered Oct 04 '22 14:10

Casey