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

11

我不明白为什么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 结构体放进一个头文件,并在两个文件中都引用它,那么你就会遇到问题。 - Pierre Emmanuel Lallemant
1
这是一个非常好的问题-让我在这个星期天动动脑筋。谢谢 - Ed Heal
2
浮点数的特殊规则通常是因为跨编译器的考虑,即在一个系统上运行但为另一个系统生成代码的编译器。处理与目标系统匹配的整数类型很容易;获取另一个系统的浮点类型的细节要复杂得多。 - Pete Becker
3
@PierreEmmanuelLallemant 我本身对代码没有任何问题,我只是想理解这种设计选择背后的原因。 - Giuseppe Pes
1
当这些类型被声明为 const 并且被初始化为一个常量表达式时,它们可以在需要编译时常量的上下文中使用。因此,C++11将此扩展到了作为 constexpr 声明的静态成员。请注意,类内初始化 不是对象的定义,它仅提供值而不是存储。 - dyp
相关/重复:https://dev59.com/JGQo5IYBdhLWcg3wDLpj/ 和 https://dev59.com/0Wkw5IYBdhLWcg3wx9aC#9657064/ - dyp
2个回答

9
这里的关键原因是,整数类型(以及枚举类型,因为在编译器内部它们变成了某种整数)可以轻松地替换并直接用作常量。换句话说,如果编译器看到struct S { static const int x = 42;},它可以立即在生成的代码中用常量42来替换它。对于必须进行“构造”的常量和/或具有更复杂使用条件的常量(考虑一个没有浮点数硬件支持的处理器——函数调用以加载和存储浮点数值等),语言不能指定允许这样做。
如果你将struct Node声明与static const std::string S = "test";一起包含,编译器应该在多少个地方存储Node::S呢?当它最终将你的三个翻译单元链接成一个程序时,它应该使用哪一个?如果你const_castNode::S并修改它会发生什么呢?后者假定你有一个不会导致崩溃的环境,尽管这是未定义行为,但我不确定编译器是否应该像在每个翻译单元中使用不同的值那样奇怪。
编辑: 正如评论中提到的,C++11允许使用类似的方式使用更多类型,因此随着编译器和硬件技术的改进,这些限制正在被放宽。我怀疑你永远无法static const std::map<X, Y> a = { ... },因为那是一个相当复杂的数据类型来构造...

这里的关键原因是,整数类型(以及枚举类型,因为在编译器内部它们变成了某种整数)可以轻松地被替换并直接用作常量。更一般地说,字面类型也可以这样使用——也许我们可以希望规则放宽以包括这些类型? - Chris Beck
问题在于字面值也可能是浮点数值[不确定是否还有其他类型], 而它们通常需要特殊处理 - 尤其是在硬件没有内置浮点支持的情况下。 - Mats Petersson
1
@ChrisBeck "will be relaxed" -> "@ChrisBeck已经放宽了要求"。 http://melpon.org/wandbox/permlink/1qxlfeqKMVWoeti7 更一般地说,所有字面类型,[class.static.data]p3。 - dyp

0

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

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接