Static constant string (class member)
我想要一个类的私有静态常量(在本例中是一个形状工厂)。
我想要类似的东西。
1 2 3 4 | class A { private: static const string RECTANGLE ="rectangle"; } |
不幸的是,我从C++(G++)编译器中得到了各种错误,例如:
ISO C++ forbids initialization of
member ‘RECTANGLE’invalid in-class initialization of static data member of non-integral type ‘std::string’
error: making ‘RECTANGLE’ static
这告诉我,这种构件设计不符合标准。如何在不使用define指令的情况下拥有私有文字常量(或者可能是公共的)(我想避免数据全球化的丑陋!)
感谢您的帮助。
必须在类定义之外定义静态成员,并在那里提供初始值设定项。
弗斯特
1 2 3 4 5 | // In a header file (if it is in a header file in your case) class A { private: static const string RECTANGLE; }; |
然后
1 2 | // In one of the implementation files const string A::RECTANGLE ="rectangle"; |
最初尝试使用的语法(类定义中的初始值设定项)只允许与整型和枚举类型一起使用。
从C++ 17开始,您还有另一种选择,它与原始声明非常相似:内联变量
1 2 3 4 5 | // In a header file (if it is in a header file in your case) class A { private: inline static const string RECTANGLE ="rectangle"; }; |
不需要其他定义。
在C++ 11中,你现在可以做:
1 2 3 4 | class A { private: static constexpr const char* STRING ="some useful string constant"; }; |
在类定义中,只能声明静态成员。它们必须在类外定义。对于编译时整型常量,标准会做出异常,您可以"初始化"成员。不过,这仍然不是一个定义。例如,如果没有定义,获取地址将无法工作。
我想说的是,我没有看到使用std::string代替const char[]作为常量的好处。std::string很好,但它需要动态初始化。所以,如果你写一些像
1 | const std::string foo ="hello"; |
在命名空间范围内,foo的构造函数将在主启动执行之前运行,并且此构造函数将在堆内存中创建常量"hello"的副本。除非您真的需要矩形是一个std::string,否则您也可以编写
1 2 3 4 5 6 7 | // class definition with incomplete static member could be in a header file class A { static const char RECTANGLE[]; }; // this needs to be placed in a single translation unit only const char A::RECTANGLE[] ="rectangle"; |
那里!没有堆分配,没有复制,没有动态初始化。
干杯。
这只是额外的信息,但是如果您真的想在头文件中使用字符串,请尝试如下操作:
1 2 3 4 5 6 7 8 9 10 | class foo { public: static const std::string& RECTANGLE(void) { static const std::string str ="rectangle"; return str; } }; |
尽管我怀疑这是推荐的。
在C++ 17中,可以使用内联变量:
1 2 3 4 | class A { private: static inline const std::string my_string ="some useful string constant"; }; |
请注意,这与Abyss.7的回答不同:这一个定义了实际的
To use that in-class initialization
syntax, the constant must be a static
const of integral or enumeration type
initialized by a constant expression.
这就是限制。因此,在本例中,您需要在类外部定义变量。请从@andreyt查询答案
类静态变量可以在头中声明,但必须在.cpp文件中定义。这是因为一个静态变量只能有一个实例,而编译器无法决定将它放在哪个生成的对象文件中,所以您必须做出决定。
用C++ 11中的声明保持静态值的定义可以使用嵌套静态结构。在这种情况下,静态成员是一个结构,必须在.cpp文件中定义,但值在标题中。
1 2 3 4 5 6 7 8 | class A { private: static struct _Shapes { const std::string RECTANGLE {"rectangle"}; const std::string CIRCLE {"circle"}; } shape; }; |
不是初始化单个成员,而是在.cpp中初始化整个静态结构:
1 | A::_Shapes A::shape; |
使用访问值
1 | A::shape.RECTANGLE; |
或者——因为成员是私有的,并且只用于
1 | shape.RECTANGLE; |
请注意,此解决方案仍然存在以下问题:静态变量的初始化。当静态值用于初始化另一个静态变量,第一个变量可能未初始化,然而。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | // 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所述,如果变量的值可以在编译时计算,那么也可以使用
1 2 3 4 5 6 7 8 | 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. } |
您可以选择上面提到的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | //in a header class A{ static string s; public: static string getS(); }; //in implementation string A::s; namespace{ bool init_A_s(){ A::s = string("foo"); return true; } bool A_s_initialized = init_A_s(); } string A::getS(){ if (!A_s_initialized) A_s_initialized = init_A_s(); return s; } |
记住只使用
顺便说一句,在上面的答案"static const std::string rectangle()const"中,静态函数不能是
可能只做:
1 2 3 | static const std::string RECTANGLE() const { return"rectangle"; } |
或
1 | #define RECTANGLE"rectangle" |
当前标准只允许对静态常量整型进行此类初始化。所以你需要按照安德烈的解释去做。但是,这将在下一个标准中通过新的成员初始化语法提供。
快速前进到2018和C++ 17。
- 不要使用std::string,使用std::string_查看文本
- 请注意下面的"constexpr"。这也是一种"编译时"机制。
- 没有内联并不意味着重复
- 不需要cpp文件
仅在编译时静态断言'works'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16using namespace std::literals;
namespace STANDARD {
constexpr
inline
auto
compiletime_static_string_view_constant() {
// make and return string view literal
// will stay the same for the whole application lifetime
// will exhibit standard and expected interface
// will be usable at both
// runtime and compile time
// by value semantics implemented for you
auto when_needed_ = "compile time"sv;
return when_needed_ ;
}};
以上是一个正确合法的C++公民标准。它可以很容易地涉及到任何和所有std::算法、容器、实用程序等。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // test the resilience auto return_by_val = []() { auto return_by_val = []() { auto return_by_val = []() { auto return_by_val = []() { return STANDARD::compiletime_static_string_view_constant(); }; return return_by_val(); }; return return_by_val(); }; return return_by_val(); }; // actually a run time _ASSERTE(return_by_val() =="compile time"); // compile time static_assert( STANDARD::compiletime_static_string_view_constant() =="compile time" ); |
享受标准C++