Deq*_*ing 9 c++ class static-members
看起来我可以初始化一个POD静态const成员,但不是其他类型:
struct C {
static const int a = 42; // OK
static const string b = "hi"; // compile error
};
Run Code Online (Sandbox Code Playgroud)
为什么?
该语法initializer in the class definition仅适用于整型和枚举类型。对于std::string,它必须在类定义之外定义并在那里初始化。
struct C {
static const int a = 42;
static const string b;
};
const string C::b = "hi"; // in one of the .cpp files
Run Code Online (Sandbox Code Playgroud)
static members必须在一个翻译单元中定义才能满足一个定义规则。如果 C++ 允许下面的定义;
struct C {
static const string b = "hi";
};
Run Code Online (Sandbox Code Playgroud)
b 将在包含头文件的每个翻译单元中定义。
C++ 只允许在类声明中定义const static数据成员integral或enumeration类型作为快捷方式。const static不能定义其他类型的数据成员的原因是需要非平凡的初始化(需要调用构造函数)。
string不是原始类型(如int),而是一个类.
不允许这样做是明智的; statics 的初始化发生在之前main.构造函数可以调用初始化时可能无法使用的各种函数.
我将在 C++98 和 C++11 上总结关于直接类初始化的规则:
以下代码在 C++03 中是非法的,但在 C++11 中如您所料。在 C++11 中,您可以将其视为被注入到 POD 的每个构造函数中的初始值设定项,除非该构造函数设置了另一个值。
struct POD {
int integer = 42;
float floating_point = 4.5f;
std::string character_string = "Hello";
};
Run Code Online (Sandbox Code Playgroud)
使字段可变静态成员将破坏两个标准中的代码,这是因为static保证只有一个变量副本,因此我们必须在一个文件中声明成员,就像我们对全局变量所做的一样使用引用使用 extern 关键字。
// This does not work
struct POD {
static int integer = 42;
static float floating_point = 4.5f;
static std::string character_string = "Hello";
};
int POD::integer = 42;
float POD::floating_point = 4.5f;
std::string POD::character_string = "Hello";
// This works
struct POD {
static int integer;
static float floating_point;
static std::string character_string;
};
int POD::integer = 42;
float POD::floating_point = 4.3f;
std::string POD::character_string = "hello";
Run Code Online (Sandbox Code Playgroud)
如果我们试图让它们, const 静态成员出现一个新的规则数组:
struct POD {
static const int integer = 42; // Always works
static constexpr float floating_point = 4.5f; // Works in C++11 only.
static const std::string character_string = "Hello"; // Does not work.
constexpr static const std::string character_string = "Hello"; // Does not work (last checked in C++11)
// Like some others have also mentioned, this works.
static const std::string character_string;
};
// In a sourcefile:
const std::string POD::character_string = "Hello";
Run Code Online (Sandbox Code Playgroud)
因此,从 C++11 开始,允许将非整数平凡类型的静态常量设为变量。不幸的是,字符串不符合要求,因此即使在 C++11 中我们也无法初始化 constexpr std::strings。
尽管如此,一切都没有丢失,正如本文提到的答案,您可以创建一个字符串类函数作为字符串文字。
注意!请注意,这是最好的元编程,如果在类中将对象声明为 constexpr static,那么一旦进入运行时,就找不到该对象。我还没弄明白为什么,请随时发表评论。
// literal string class, adapted from: http://en.cppreference.com/w/cpp/language/constexpr
class conststr {
const char * p;
std::size_t sz;
public:
template<std::size_t N>
constexpr conststr(const char(&a)[N]) : p(a), sz(N-1) {}
// constexpr functions signal errors by throwing exceptions from operator ?:
constexpr char operator[](std::size_t n) const {
return n < sz ? p[n] : throw std::out_of_range("");
}
constexpr std::size_t size() const { return sz; }
constexpr bool operator==(conststr rhs) {
return compare(rhs) == 0;
}
constexpr int compare(conststr rhs, int pos = 0) {
return ( this->size() < rhs.size() ? -1 :
( this->size() > rhs.size() ? 1 :
( pos == this->size() ? 0 :
( (*this)[pos] < rhs[pos] ? -1 :
( (*this)[pos] > rhs[pos] ? 1 :
compare(rhs, pos+1)
)
)
)
)
);
}
constexpr const char * c_str() const { return p; }
};
Run Code Online (Sandbox Code Playgroud)
现在你可以直接在你的类中声明一个 conststr :
struct POD {
static const int integer = 42; // Always works
static constexpr float floating_point = 4.5f; // Works in C++11 only.
static constexpr conststr character_string = "Hello"; // C++11 only, must be declared.
};
int main() {
POD pod;
// Demonstrating properties.
constexpr conststr val = "Hello";
static_assert(val == "Hello", "Ok, you don't see this.");
static_assert(POD::character_string == val, "Ok");
//static_assert(POD::character_string == "Hi", "Not ok.");
//static_assert(POD::character_string == "hello", "Not ok.");
constexpr int compare = val.compare("Hello");
cout << compare << endl;
const char * ch = val.c_str(); // OK, val.c_str() is substituted at compile time.
cout << ch << endl; // OK
cout << val.c_str() << endl; // Ok
// Now a tricky one, I haven't figured out why this one does not work:
// cout << POD::character_string.c_str() << endl; // This fails linking.
// This works just fine.
constexpr conststr temp = POD::character_string;
cout << temp.c_str() << endl;
}
Run Code Online (Sandbox Code Playgroud)