Le variabili statiche della classe possono essere dichiarate nell'intestazione ma devono essere definite in un file .cpp. Questo perché può esserci solo un'istanza di una variabile statica e il compilatore non può decidere in quale file oggetto generato metterlo, quindi devi prendere la decisione.
Per mantenere la definizione di un valore statico con la dichiarazione in C ++ 11 è possibile utilizzare una struttura statica nidificata. In questo caso il membro statico è una struttura e deve essere definito in un file .cpp, ma i valori sono nell'intestazione.
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
Invece di inizializzare i singoli membri l'intera struttura statica viene inizializzata in .cpp:
A::_Shapes A::shape;
Si accede ai valori con
A::shape.RECTANGLE;
oppure - poiché i membri sono privati e devono essere utilizzati solo da A - con
shape.RECTANGLE;
Si noti che questa soluzione soffre ancora del problema dell'ordine di inizializzazione delle variabili statiche. Quando si utilizza un valore statico per inizializzare un'altra variabile statica, la prima potrebbe non essere ancora inizializzata.
// 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 questo caso le intestazioni delle variabili statiche conterranno {""} o {".h", ".hpp"}, a seconda dell'ordine di inizializzazione creato dal linker.
Come accennato da @ abyss.7, puoi anche utilizzare constexpr
se il valore della variabile può essere calcolato al momento della compilazione. Ma se dichiari le tue stringhe con static constexpr const char*
e il tuo programma usa std::string
altrimenti ci sarà un overhead perché un nuovo std::string
oggetto verrà creato ogni volta che usi una tale costante:
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.
}