I\'d like to define a constant char* in my header file for my .cpp file to use. So I\'ve tried this:
private:
static const char *SOMETHING = \"sommething\";
The error is that you cannot initialize a static const char*
within the class. You can only initialize integer variables there.
You need to declare the member variable in the class, and then initialize it outside the class:
// header file
class Foo {
static const char *SOMETHING;
// rest of class
};
// cpp file
const char *Foo::SOMETHING = "sommething";
If this seems annoying, think of it as being because the initialization can only appear in one translation unit. If it was in the class definition, that would usually be included by multiple files. Constant integers are a special case (which means the error message perhaps isn't as clear as it might be), and compilers can effectively replace uses of the variable with the integer value.
In contrast, a char*
variable points to an actual object in memory, which is required to really exist, and it's the definition (including initialization) which makes the object exist. The "one definition rule" means you therefore don't want to put it in a header, because then all translation units including that header would contain the definition. They could not be linked together, even though the string contains the same characters in both, because under current C++ rules you've defined two different objects with the same name, and that's not legal. The fact that they happen to have the same characters in them doesn't make it legal.
You need to define static variables in a translation unit, unless they are of integral types.
In your header:
private:
static const char *SOMETHING;
static const int MyInt = 8; // would be ok
In the .cpp file:
const char *YourClass::SOMETHING = "something";
C++ standard, 9.4.2/4:
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression. In that case, the member can appear in integral constant expressions within its scope. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.
Constant initializer allowed by C++ Standard only for integral or enumeration types. See 9.4.2/4 for details:
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. The member shall still be defined in a name- space scope if it is used in the program and the namespace scope definition shall not contain an initializer.
And 9.4.2/7:
Static data members are initialized and destroyed exactly like non-local objects (3.6.2, 3.6.3).
So you should write somewhere in cpp file:
const char* SomeClass::SOMETHING = "sommething";
With C++11 you can use the constexpr
keyword and write in your header:
private:
static constexpr const char* SOMETHING = "something";
Notes:
constexpr
makes SOMETHING
a constant pointer so you cannot write
SOMETHING = "something different";
later on.
Depending on your compiler, you might also need to write an explicit definition in the .cpp file:
constexpr const char* MyClass::SOMETHING;
class A{
public:
static const char* SOMETHING() { return "something"; }
};
I do it all the time - especially for expensive const default parameters.
class A{
static
const expensive_to_construct&
default_expensive_to_construct(){
static const expensive_to_construct xp2c(whatever is needed);
return xp2c;
}
};
To answer the OP's question about why it is only allowed with integral types.
When an object is used as an lvalue (i.e. as something that has address in storage), it has to satisfy the "one definition rule" (ODR), i.e it has to be defined in one and only one translation unit. The compiler cannot and will not decide which translation unit to define that object in. This is your responsibility. By defining that object somewhere you are not just defining it, you are actually telling the compiler that you want to define it here, in this specific translation unit.
Meanwhile, in C++ language integral constants have special status. They can form integral constant expressions (ICEs). In ICEs integral constants are used as ordinary values, not as objects (i.e. it is not relevant whether such integral value has address in the storage or not). In fact, ICEs are evaluated at compile time. In order to facilitate such a use of integral constants their values have to be visible globally. And the constant itself don't really need an actual place in the storage. Because of this integral constants received special treatment: it was allowed to include their initializers in the header file, and the requirement to provide a definition was relaxed (first de facto, then de jure).
Other constant types has no such properties. Other constant types are virtually always used as lvalues (or at least can't participate in ICEs or anything similar to ICE), meaning that they require a definition. The rest follows.