18

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.

4
  • 5
    Note that v is not a pointer, it's an array. Commented May 1, 2014 at 8:58
  • Seems to be perfectly legal: ideone.com/oMwXAj Commented May 1, 2014 at 9:01
  • possible duplicate of `x[0] == 1` constant expression in C++11 when x is const int[]? Commented May 1, 2014 at 9:06
  • @πάνταῥεῖ interesting, because my clang (3.4) won't link without also providing a def to provision the array (but has no problems with the integer constant). how odd. regardless, it still compiles, just puking on the link. Commented May 1, 2014 at 9:08

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

Comments

3
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.

Comments

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

This fragment by itself is certainly legal as far as I can tell. Section 7.1.5 [dcl.constexpr] of the C++11 standard says that

The constexpr specifier shall be applied only to... the declaration of a static data member of a literal type

and a literal type is defined in 3.9:

A type is a literal type if it is:

— a scalar type; or...

— an array of literal type

So static constexpr double v[2] = { ... } is certainly valid as far as I can tell.

As to whether the members of the array are constexpr... I'm not sure. If we declare

constexpr double d = Parameter::v[1];

then both g++ and clang compile it okay, but the clang version fails to link with an undefined reference to Parameters::v. I don't know whether this points to a Clang bug, or whether the construct is invalid.

3 Comments

Technically, I don't think the members of the array can be constexpr, as they're not complete objcets. But you cannot access them directly anyway, you can only acces them through the expression Parameters::v[0] (or 1). And that satisifies all the requirements of a constant expression.
@Angew But from a practical point of view, the address of Parameters::v will be set by the linker or runtime, and not known to the compiler. So naively, *(Parameters::v + 1) as a constexpr would be a bit tricky?
C++11[expr.const]§2,3 define the reuqirements on constant expressions, and the array dereference does not violate any of them. So it's a constant expression.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.