7

Why I cannot initialize a static const char* in the header file? In my code I have in my Class header:

static const char* xml_ID_TAG;

and in the cpp:

const char* Class::xml_ID_TAG = "id";

The xml_ID_TAG variable contains the attribute string of an XML document. Since it's static, const, primitive type (char*), etc... I can't figure out why the compiler forbid to write something like:

static const char* xml_ID_TAG = "id";

I'm using MSVC2013 compiler, giving for the example above the error: "Error: a member with an in-class initializer must be const"

ABCplus
  • 3,981
  • 3
  • 27
  • 43
  • Only `static const` integral members can be defined inside a class body. This is to prevent ODR violations. – Simple Jul 04 '14 at 10:47

3 Answers3

17

Generally speaking you must define your static members in precisely one translation unit, and the language helps to enforce this by prohibiting you from writing an initialiser for such a member inside the surrounding class definition:

struct T
{
   static int x = 42;
   // ^ error: ISO C++ forbids in-class initialization of
   // non-const static member 'T::x'
};

However, a special exception is made for constants, for convenience:

struct T
{
   static const int x = 42;
   // ^ OK
};

Note that in most cases you still need to define the constant (in your .cpp file would be the best place):

const int T::x;

[C++11: 9.4.2/3]:] If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression (5.19). 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.


Now, your member is not an int and even a const char* const is not of an "integral type":

struct T
{
   static const char* const str = "hi";
   // ^ error: 'constexpr' needed for in-class initialization of
   // static data member 'const char* const T::str' of non-integral type
};

but it is of a "literal type"; the upshot for you is that if you write it like this:

static constexpr const char* const xml_ID_TAG = "id";
//     ^^^^^^^^^             ^^^^^

you should be okay. (Note that you will still need to define it, until C++17.)

This probably makes more sense anyway: why would you want to change the pointer?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Nope, I tried the last solution (static constexpr const char * const foo="foo") and it gives me link errors in some cases if I don't define it. – galinette Jun 14 '19 at 09:36
  • @galinette Yeah [you still need to define it](https://stackoverflow.com/a/51051942/560648) (though not since C++17!). Thanks, will clarify. – Lightness Races in Orbit Jun 14 '19 at 10:27
5

Because string literals (eg "id") are stored per file compilation unit. So if they are in a header file, there's a different instance stored for each source file that includes it. So your 'initialisation' is trying to store different values in a static variable for each compilation unit that #includes it..

Paul Evans
  • 27,315
  • 3
  • 37
  • 54
4

"Since it's [...] const" - Nope.

You need const char* const - assuming you're using C++11.

Otherwise you have to put the definition in the cpp file.

See: How to initialize a static const member in C++?

Community
  • 1
  • 1
Karoly Horvath
  • 94,607
  • 11
  • 117
  • 176