Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are constexpr array members compile time constants?

Tags:

c++

c++11

Is the code fragment

struct Parameters {
   static constexpr int n = 2;
   static constexpr double v[n] = {4.0, 5.0};
};

legal C++11? And, if so, are Parameters::v[0] and Parameters::v[1] compile time constants or is just the pointer Parameters::v itself a constexpr (whatever that would mean at compile time)?

As you can see I am generally a bit confused about constexpr arrays and their initialization in classes/structs. Please feel free to not only answer my specific question but also to mention common pitfalls and the like concerning this topic.

like image 596
o.svensson Avatar asked May 01 '14 08:05

o.svensson


2 Answers

I see no problem with the construct. Quoting C++11, [dcl.constexpr]:

§1 The constexpr specifier shall be applied only to the definition of a variable, the declaration of a function or function template, or the declaration of a static data member of a literal type (3.9). ...

§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. If it is initialized by a constructor call, that call shall be a constant expression (5.19). Otherwise, or if a constexpr specifier is used in a reference declaration, every full-expression that appears in its initializer shall be a constant expression. Each implicit conversion used in converting the initializer expressions and each constructor call used for the initialization shall be one of those allowed in a constant expression (5.19).

double is a literal type, and so is an array of literal types. Which means that v[0] and v[1] from your code are indeed constant expressions.

like image 167
Angew is no longer proud of SO Avatar answered Sep 18 '22 03:09

Angew is no longer proud of SO


struct Parameters {
  static constexpr int n = 2;
  static constexpr double v[n] = {4.0, 5.0};
};

int main() {
  constexpr int a = Parameters::v[0];
  return 0;
}

This code on gcc 4.8.2 compiles into the following:

0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   c7 45 fc 04 00 00 00    mov    DWORD PTR [rbp-0x4],0x4
   b:   b8 00 00 00 00          mov    eax,0x0
  10:   5d                      pop    rbp
  11:   c3                      ret 

So yes, it is a compile time constant.

clang 3.4 produces similar code:

0000000000000000 <main>:
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
   4:   b8 00 00 00 00          mov    eax,0x0
   9:   c7 45 fc 00 00 00 00    mov    DWORD PTR [rbp-0x4],0x0
  10:   c7 45 f8 04 00 00 00    mov    DWORD PTR [rbp-0x8],0x4
  17:   5d                      pop    rbp
  18:   c3                      ret

Again, it is a compile time constant.

Everything was compiled with -O0.

P.S.: If a is declared const, then for gcc nothing changes but for clang does, the value 4 is not mov'ed directly as if was a compile time constant.

If a is declared neither const or constexpr then both compilers fail to treat Parameters::v[0] as a compile time constant.

like image 39
Theodoros Theodoridis Avatar answered Sep 19 '22 03:09

Theodoros Theodoridis