为啥只能在 C++ 类中初始化整数或枚举类型?

Posted

技术标签:

【中文标题】为啥只能在 C++ 类中初始化整数或枚举类型?【英文标题】:Why only integral or enum type can be initialised in a C++ class?为什么只能在 C++ 类中初始化整数或枚举类型? 【发布时间】:2016-01-17 14:14:32 【问题描述】:

我不明白为什么 C++ 只允许在类声明中定义整型和枚举(枚举也是整型)。而所有其他类型,包括浮点类型(即 double 和 float),都必须在类声明之外定义。显然这一定是一个原因,但我无法弄清楚。

代码示例:

#include <iostream>

using namespace std;

struct Node 

  static const int c = 0;  // Legal Definition 
  static const long l = 0l; // Legal Definition 
  static const short s = 0; // Legal Definition 

  static const float f = 0.0f; // Illegal definition 
  static const string S = "Test"; // Illegal definition 

  static const string JOB_TYPE; // Legal declaration
  static const float f; // Legal declaration 
  static const double d; // Legal declaration 
;

const string Node::JOB_TYPE = "Test"; // correct definition
const float Node::f = 0.0f;  // correct definition 
const double Node::d = 0.0;  // correct definition 

int main() 

  cout << Node::c << endl;
  cout << Node::c << endl;

  cout << Node::JOB_TYPE << endl;

  cout << Node::f << endl;


【问题讨论】:

如果您将Node 结构放在标题中并将其包含在2个文件中,您将遇到问题。 这是一个非常好的问题 - 这个星期天让我的脑细胞发疯了。谢谢 浮点的特殊规则通常是因为对交叉编译器的担忧,即在一个系统上运行但为另一个系统生成代码的编译器。处理与目标系统匹配的整数类型很容易;获取另一个系统的浮点类型的详细信息要复杂得多。 @PierreEmmanuelLallemant 我对代码本身没有任何问题。我只是想了解这种设计选择背后的原因。 这些类型,当声明为const 并使用常量表达式初始化时,可以在需要编译时常量的上下文中使用。因此,C++11 为声明为constexpr 的静态成员扩展了此功能。请注意,类内初始化不是对象的定义,它只是提供一个值而不是存储。 【参考方案1】:

这里的关键原因是整数类型(以及enum,因为在编译器内部它们变成了某种整数)可以很容易地替换并直接用作常量。

换句话说,struct S static const int x = 42;,如果编译器看到S::x,它可以立即将其替换为生成代码中的常量42。这并不(总是)适用于float,当然也不适用于依赖于构造函数的类型,例如std::string - 编译器无法在不调用new(或std::string::allocator)的情况下为std::string 分配内存。因此,对于必须“构造”和/或对如何使用它们有更复杂标准的常量(想想一个没有硬件支持浮点的处理器——加载和存储浮点值的函数调用,等),语言不能规定它应该被允许这样做。

如果您在static const std::string S = "test"; 中包含struct Node 声明,编译器应将Node::S 存储在多少个位置?当它最终将您的三个翻译单元链接到一个程序中时,应该使用哪一个 - 还是应该使用不同的?如果你 const_cast Node::S 并修改它会发生什么?后者假设您有一个不会导致崩溃的环境,这是完全合理的,虽然这是未定义的行为,但我不确定编译器是否应该让它像在每个翻译单元中使用不同的值一样奇怪那个案子……

编辑: 如 cmets 中所述,C++11 确实允许以类似方式使用更多类型,因此随着编译器和硬件技术的改进,限制正在放宽。我怀疑你永远无法static const std::map&lt;X, Y&gt; a = ... tho',因为这是一个相当复杂的数据类型来构造......

【讨论】:

“这里的关键原因是整数类型(和枚举,因为在编译器内部它们变成某种整数)可以很容易地替换并直接用作常量。”更一般地说,可以使用文字类型这样 - 也许我们可以希望规则会放宽以包括这些? 嗯,问题是文字也可能是浮点值[不确定是否还有其他值],并且它们通常需要特殊处理 - 特别是在没有内置支持的硬件上浮点数。 @ChrisBeck“会放松”->“会放松”。 melpon.org/wandbox/permlink/1qxlfeqKMVWoeti7 更一般地说,所有文字类型,[class.static.data]p3【参考方案2】:

std::string 的初始化需要在运行时执行一些代码。

使用字符串字面量初始化指针需要将字符串放在内存中的某个位置,也在运行时。

【讨论】:

以上是关于为啥只能在 C++ 类中初始化整数或枚举类型?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 C++ 允许通过指针访问枚举?

C++ 无法从枚举转换为 LPCTSTR [关闭]

C++中类的一个数据成员是枚举类型,那么它在类中该怎么定义?

C ++错误:“表达式必须具有整数或枚举类型” [重复]

C++中的enum枚举

枚举类型