3

I'm having some difficulties with static constexpr attributes: it works with integral types, with enum class members, but when I try to do it with a statically initialized integral array it fails at linking saying undefined reference to S::a inside main.

That is with either clang 3.9 or g++ 6.3, and ld 2.27.90; and all that with -std=c++14.

Here is the quickest snippet to reproduce this:

struct S { static constexpr int a[5] = {0}; }; int main() { S s{}; [[gnu::unused]] int b = s.a[0]; // force S stuff to be emitted return 0; } 

Thank you for any suggestion you may have for this situation.

2
  • You need to define your object; at namespace scope: constexpr int S::a[5]; Commented Feb 19, 2017 at 16:38
  • @ildjarn thanks ! but do you know why I do have to do this for arrays but not for other stuff like plain integral types ? Commented Feb 19, 2017 at 17:04

1 Answer 1

5

Consider this code:

enum class E { foo, bar }; struct S { static constexpr int a[5] = {0}; static constexpr int b = 42; static constexpr E e = foo; }; 

All of above are declarations, and are not definitions. For each one, you must provide a definition:

int S::a[5]; int S::b; E S::e; 

it works with integral types, with enum class members

This works more or less by accident. Specifically, it works because you never have a context where the address of that variable is taken (never ODR-use the variable).

Often I see people adding an innocent-looking call to std::max, and suddenly discovering that they didn't provide a definition. That is:

int main() { printf("%d\n", S::b); // works fine int x = std::max(1, S::b); // fails to link in non-optimized build. } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.