我想有一个类的私有静态常量(在这种情况下是一个形状工厂)。
我想要这样的东西。
class A {
private:
static const string RECTANGLE = "rectangle";
}
不幸的是,我从c++ (g++)编译器得到了各种各样的错误,比如:
ISO c++禁止初始化
“矩形”成员
非整型静态数据成员' std::string '的类内初始化无效
错误:使“矩形”静态
这说明这种构件设计是不符合标准的。如何在不使用#define指令的情况下获得私有文字常量(或者公共常量)(我想避免数据全局的丑陋!)
任何帮助都是感激的。
快进到2018年和c++ 17。
do not use std::string, use std::string_view literals
please do notice the 'constexpr' bellow. This is also an "compile time" mechanism.
no inline does not mean repetition
no cpp files are not necessary for this
static_assert 'works' at compile time only
using 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::算法、容器、实用程序等。例如:
// 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++吧
在类定义内部,只能声明静态成员。它们必须在类之外定义。对于编译时整型常量,标准给出了可以“初始化”成员的例外。但它仍然不是一个定义。例如,如果没有定义,就不能使用地址。
我想提一下,对于常量,我没有看到使用std::string而不是const char[]的好处。string很好,但它需要动态初始化。所以,如果你写
const std::string foo = "hello";
在命名空间范围内,foo的构造函数将在main开始执行之前运行,该构造函数将在堆内存中创建常量“hello”的副本。除非你真的需要RECTANGLE作为std::string,否则你也可以这样写
// 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";
在那里!没有堆分配,没有复制,没有动态初始化。
干杯,年代。
快进到2018年和c++ 17。
do not use std::string, use std::string_view literals
please do notice the 'constexpr' bellow. This is also an "compile time" mechanism.
no inline does not mean repetition
no cpp files are not necessary for this
static_assert 'works' at compile time only
using 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::算法、容器、实用程序等。例如:
// 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++吧
你可以使用上面提到的const char*解决方案,但是如果你总是需要字符串,你将会有很多开销。
另一方面,静态字符串需要动态初始化,因此如果你想在另一个全局/静态变量初始化期间使用它的值,你可能会遇到初始化顺序的问题。为了避免这种情况,最便宜的方法是通过getter访问静态字符串对象,getter检查对象是否已初始化。
//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;
}
记住只使用A::getS()。因为任何线程只能由main()启动,并且A_s_initialized在main()之前初始化,所以即使在多线程环境中也不需要锁。默认情况下A_s_initialized为0(在动态初始化之前),因此如果在s初始化之前使用getS(),则可以安全地调用init函数。
顺便说一句,在上面的答案:“static const std::string RECTANGLE() const”,静态函数不能是const,因为它们不能改变任何对象的状态(没有this指针)。