看起来我可以初始化一个POD静态const成员,但不是其他类型:
struct C {
static const int a = 42; // OK
static const string b = "hi"; // compile error
};
为什么?
答案 0 :(得分:5)
string
不是原始类型(如int
),但是是一个类。
禁止这是明智的; static
的初始化发生在main
之前。构造函数可以调用初始化时可能无法使用的各种函数。
答案 1 :(得分:4)
语法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
必须在一个翻译单元中定义 static members
才能实现一个定义规则。如果C ++允许以下定义;
struct C {
static const string b = "hi";
};
b
将在包含头文件的每个翻译单元中定义。
C ++只允许在类声明中将const static
或integral
类型的enumeration
数据成员定义为快捷方式。无法定义其他类型的const static
数据成员的原因是需要进行非平凡的初始化(需要调用构造函数)。
答案 2 :(得分:2)
我将总结关于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";
};
使字段可变静态成员将破坏两个标准中的代码,这是因为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";
如果我们尝试制作它们,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";
因此,从C ++ 11开始,允许使非整数平凡类型的静态常量变量。不幸的是,字符串不符合要求,因此即使在C ++ 11中也无法初始化constexpr std :: strings。
尽管如此,作为对this post提及的答案,你可以创建一个字符串类函数作为字符串文字。
NB!请注意,如果对象在类中声明为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; }
};
现在您可以直接在您的班级中声明一个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;
}
答案 3 :(得分:0)
在 C++17 中:
如果您可以使用 static constexpr
,您将获得所需的结果,但如果您不能:使用 C++17 引入的 inline variable
。
在您的情况下,由于 std::string
没有 constexpr
构造函数,因此解决方案是 inline static const std::string
示例:
#include <iostream>
int foo() { return 4;}
struct Demo
{
inline static const int i = foo();
inline static const std::string str = "info";
};
int main() {
std::cout << Demo::i << " " << Demo::str<< std::endl;
}