The class static variables can be declared in the header but must be defined in a .cpp file. This is because there can be only one instance of a static variable and the compiler can't decide in which generated object file to put it so you have to make the decision, instead.
To keep the definition of a static value with the declaration in C++11
a nested static structure can be used. In this case the static member
is a structure and has to be defined in a .cpp file, but the values
are in the header.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Instead of initializing individual members the whole static structure is initialized in .cpp:
A::_Shapes A::shape;
The values are accessed with
A::shape.RECTANGLE;
or -- since the members are private and are meant to be used only from A -- with
shape.RECTANGLE;
Note that this solution still suffers from the problem of the order of
initialization of the static variables. When a static value is used to
initialize another static variable, the first may not be initialized,
yet.
// file.h
class File {
public:
static struct _Extensions {
const std::string h{ ".h" };
const std::string hpp{ ".hpp" };
const std::string c{ ".c" };
const std::string cpp{ ".cpp" };
} extension;
};
// file.cpp
File::_Extensions File::extension;
// module.cpp
static std::set<std::string> headers{ File::extension.h, File::extension.hpp };
In this case the static variable headers will contain either { "" }
or { ".h", ".hpp" }, depending on the order of initialization created by the linker.
As mentioned by @abyss.7 you could also use constexpr
if the value of the variable can be computed at compile time. But if you declare your strings with static constexpr const char*
and your program uses std::string
otherwise there will be an overhead because a new std::string
object will be created every time you use such a constant:
class A {
public:
static constexpr const char* STRING = "some value";
};
void foo(const std::string& bar);
int main() {
foo(A::STRING); // a new std::string is constructed and destroyed.
}