Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

x[0] == 1 constant expression in C++11 when x is const int[]?

Is the following C++11 program ill-formed?

const int x[] = {1,2,3};

static_assert(x[0] == 1, "yay");

int main() {}

gcc and clang seem to think so, but why isn't x[0] == 1 a constant expression?

x[0] == 1
subscript operator
*(x+0) == 1
array-to-pointer conversion (int* p = x)
*(p+0) == 1
pointer addition
*p == 1
indirection (lvalue y = x[0])
y == 1
lvalue-to-rvalue conversion:

a non-volatile glvalue (yes, x[0] is a glvalue and non-volatile) of integral (yes it has type const int) or enumeration type that refers to a non-volatile const object (yes it has type const int) with a preceding initialization (yes initialized with 1), initialized with a constant expression (yes 1 is constant expression)

Seems true, the first element of the x array satisfies these conditions.

1 == 1

?

Is this a compiler bug, standard defect, or am i missing something?

What part of 5.19 [expr.const] says this isn't a constant expression?

like image 748
Andrew Tomazos Avatar asked Sep 19 '13 19:09

Andrew Tomazos


People also ask

What is constant expression in c#?

A constant expression is an expression that can be fully evaluated at compile time. Therefore, the only possible values for constants of reference types are string and a null reference. The constant declaration can declare multiple constants, such as: C# Copy.

What is const expression in C++?

A constant value is one that doesn't change. C++ provides two keywords to enable you to express the intent that an object is not intended to be modified, and to enforce that intent. C++ requires constant expressions — expressions that evaluate to a constant — for declarations of: Array bounds.

Can we use extern const in C?

Yes, you can use them together.


1 Answers

In 5.19:

A [...]expression is a constant expression unless it involves one of the following [...]:

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

    • a glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
    • a glvalue of literal type that refers to a non-volatile object defined with constexpr, or that refers to a sub-object of such an object, or
    • a glvalue of literal type that refers to a non-volatile temporary object initialized with a constant expression

Putting it plainly, lvalue-to-rvalue conversion can only be done in constant expressions if:

  • a constant integral (or enum) declaration initialized with a constant: const int x = 3;.
  • a declaration with constexpr: constexpr int x[] = {1,2,3};.
  • a temporary object initialized with a constant expression...

Your example does include lvalue-to-rvalue conversion, but has none of these exceptions, so x is not a constant expression. If, however, you change it to:

constexpr int x[] = {1,2,3};

static_assert(x[0] == 1, "yay");

int main() {}

Then all is well.

like image 149
rodrigo Avatar answered Oct 05 '22 22:10

rodrigo