5

The following program gives me a link-time error:

#include <iostream> struct Test { static constexpr char text[] = "Text"; }; int main() { std::cout << Test::text << std::endl; // error: undefined reference to `Test::text' } 

The error message is

/tmp/main-35f287.o: In function `main': main.cpp:(.text+0x4): undefined reference to `Test::text' main.cpp:(.text+0x13): undefined reference to `Test::text' clang: error: linker command failed with exit code 1 (use -v to see invocation) 

Ok. Let's try to fix that: I add a definition outside the struct body:

#include <iostream> struct Test { static constexpr char text[] = "Text"; }; constexpr char Test::text[] = "Text"; int main() { std::cout << Test::text << std::endl; } 

Clang gives me the following error message.

main.cpp:4:35: error: static data member 'text' already has an initializer constexpr char Test::text[] = "Text"; ^ main.cpp:3:50: note: previous initialization is here struct Test { static constexpr char text[] = "Text"; }; 

Oh, well, I thought, now I know what you want:

#include <iostream> struct Test { static constexpr char text[]; }; constexpr char Test::text[] = "Text"; int main() { std::cout << Test::text << std::endl; } 

And again an error:

main.cpp:3:41: error: declaration of constexpr static data member 'text' requires an initializer struct Test { static constexpr char text[]; }; 

And there the dog bites its own tail. :(

Is there a way to use compile-time constant character arrays that are declared inside a class? The reason, I want the data inside a class, is that I need a type traits class that helps me do template stuff.

5
  • Did you mean simply struct Test { static const char text[] = "Text"; }; ? Commented Jan 14, 2016 at 14:49
  • 1
    You have tried two options - initializer outside the class, both inside and outside. Now, there is a third alternative... Commented Jan 14, 2016 at 14:51
  • 1
    This works fine: struct Test { static constexpr auto text = "Text"; }; Commented Jan 14, 2016 at 14:53
  • @vincentp Nice. This is the most concise way of writing it. Avoids duplication. Worthy to be an accepted answer. Commented Jan 14, 2016 at 15:12
  • 1
    @vincentp follows up with your comment, I asked this question stackoverflow.com/questions/34793392/… Commented Jan 14, 2016 at 15:33

2 Answers 2

8

Should work:

#include <iostream> struct Test { static constexpr char text[] = "Text"; }; constexpr char Test::text[]; int main() { std::cout << Test::text << std::endl; } 

In standard (n4140 §9.4.2/3) you can find:

A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.

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

2 Comments

Only one initialization initialization assignment.
Works for me! Thank you!
2

As said in comments, this version works fine:

struct Test { static constexpr auto text = "Text"; }; 

But text will be a const char* instead of a char[].

1 Comment

Why does it not work to make a const char[5] out of it? I mean why is there so much of a difference? This is annoying. That makes it unusable for my purposes.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.