类静态变量可以在标头中声明,但必须在.cpp文件中定义。这是因为静态变量只能有一个实例,并且编译器无法决定将其放置在哪个生成的目标文件中,因此您必须做出决定。
为了使用C ++ 11中的声明保留静态值的定义,可以使用嵌套的静态结构。在这种情况下,静态成员是结构,必须在.cpp文件中定义,但值在标头中。
class A
{
private:
static struct _Shapes {
const std::string RECTANGLE {"rectangle"};
const std::string CIRCLE {"circle"};
} shape;
};
无需初始化单个成员,而是在.cpp中初始化整个静态结构:
A::_Shapes A::shape;
通过以下方式访问值
A::shape.RECTANGLE;
或-由于成员是私有成员,并且只能从A使用-
shape.RECTANGLE;
注意,该解决方案仍然遭受静态变量的初始化顺序的问题。当使用静态值初始化另一个静态变量时,第一个静态变量可能尚未初始化。
// 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 };
在这种情况下,静态变量头将包含{“”}或{“ .h”,“ .hpp”},具体取决于链接程序创建的初始化顺序。
如@ abyss.7所述,constexpr
如果可以在编译时计算变量的值,则也可以使用。但是,如果用声明字符串,static constexpr const char*
并且程序使用了std::string
否则,则会产生开销,因为std::string
每次使用该常量时都会创建一个新对象:
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.
}