可能重复
Why can't I have a non-integral static const member in a class?
struct Example
{
static const int One = 1000; // Legal
static const short Two = 2000; // Illegal
static const float Three = 2000.0f; // Illegal
static const double Four = 3000.0; // Illegal
static const string Five = "Hello"; // Illegal
};
#2,#3,#4和#5是否有任何违法原因?
我想我知道#5的原因:编译器需要一个“真正的”字符串对象(因为它不是内置类型)并且不能盲目地将Five
替换为"Hello"
,就好像它是#define Five "Hello"
。但是,如果是这种情况,编译器是否不能在.obj文件中留下提示并告诉链接器在某处自动创建string Five
的一个实例?
对于#3和#4,特别是#2(哈哈!)......我真的看不出任何可能的原因!浮点数和双打数是内置类型,就像int一样!而short只是一个(可能)较短的整数。
编辑:我正在使用Visual Studio 2008进行编译。我认为在这种情况下所有编译器的行为都相同,但显然g ++编译得很好(#5除外)。 VS为这些片段提供的错误是:
error C2864: 'Example::Two' : only static const integral data members can be initialized within a class error C2864: 'Example::Three' : only static const integral data members can be initialized within a class error C2864: 'Example::Four' : only static const integral data members can be initialized within a class error C2864: 'Example::Five' : only static const integral data members can be initialized within a class
答案 0 :(得分:7)
int和short是合法的,如果你的编译器不允许它们,那么你的编译器就会破灭:
9.4.2 / 4:...如果静态数据成员是const整数或const 枚举类型,其声明在 类定义可以指定一个 常量初始化器,它应是一个整数常量表达式。
我认为浮点数和双精度的原因并没有特别作为C ++标准中的常量处理,就像整数类型一样,C ++标准是谨慎的,因为float和double上的算术运算可能是微妙的在编译机上不同于在执行代码的机器上。为了让编译器像(a + b)那样计算常量表达式,它需要得到运行时得到的相同答案。
对于整数而言,这不是一个问题 - 如果它不同,你可以相对便宜地模拟整数运算。但是,编译器在目标设备上模拟浮点硬件可能非常困难。如果有不同版本的芯片并且编译器不知道代码将在哪个上运行,那甚至可能是不可能的。甚至在你开始搞乱IEEE舍入模式之前就已经存在了。因此标准避免了它,因此它不必定义编译时评估何时以及如何与运行时评估不同。
正如Brian所提到的,C ++ 0x将使用constexpr
来解决这个问题。如果我对原始动机是正确的,那么大概10年就足以解决指定这些问题的困难。
答案 1 :(得分:4)
Example::One
和Example::Two
都应该为您编译,并且它们确实在您所声明的相同环境中为我编译(VS 2008)。
我不相信Example::Three
,Example::Four
应该在标准C ++中编译,但我认为有一个gcc扩展允许它。 Example::Five
不应该编译。
您可以在结构声明之后初始化它们,通常在源文件中:
const float Example::Three = 2000.0f;
const double Example::Four = 3000.0;
const string Example::Five = "Hello";
这是最便携的方式,即使您的编译器允许您在声明中定义Example::Three
和Example::Four
,我也建议您这样做。
另一种选择是简单地从相同类型的静态函数返回值。
struct Example
{
//...
static double Four() { return = 3000.0; }
//...
};
This answer也讨论了可能的原因 This answer讨论了即将推出的C ++标准如何通过constexpr
提供帮助答案 2 :(得分:1)
在C ++ 98中,只有静态const成员 可以初始化整数类型 在课堂上,初始化者必须 是一个不变的表达。这些 限制确保我们可以做到 在编译时初始化。
请参阅In-class member initializers。
§9.4.2静态数据成员
如果静态数据成员是const integral或const枚举类型,则它在类定义中的声明可以 指定一个常量初始化器,它应该是一个整型常量表达式(5.19)。在这种情况下,会员可以出现 在积分常数表达式中。如果在程序中使用该成员,则该成员仍应在命名空间范围内定义 命名空间范围定义不应包含初始化程序。
答案 3 :(得分:1)
#1和2符合标准。不幸的是,有些编译器根本不符合。这就是为什么,例如,Boost设计师不得不引入像BOOST_STATIC_CONSTANT
这样烦人的宏来生成可移植的库。如果您不想在.cpp文件中定义常量,则可移植的解决方法是使用enum
。虽然,显然在这种情况下你不能保证类型,你不能使用浮点数。
答案 4 :(得分:0)
在VS2008下,我收到以下错误:
1>.\Weapon Identification SystemDlg.cpp(223) : error C2864: 'Example::Three' : only static const integral data members can be initialized within a class
1>.\Weapon Identification SystemDlg.cpp(224) : error C2864: 'Example::Four' : only static const integral data members can be initialized within a class
1>.\Weapon Identification SystemDlg.cpp(225) : error C2864: 'Example::Five' : only static const integral data members can be initialized within a class
很糟糕,但我想如果你的编译器拒绝,你就不得不这样做......我不知道这是一个规范的东西,但我确定有人会纠正我......
答案 5 :(得分:0)
重新浮点初始化器,C ++ 98规范就是这样说的(5.19):
浮动文字只有在转换为整数或枚举类型时才会出现。
答案 6 :(得分:0)
正如其他人所发现的那样,C ++标准禁止使用浮点值初始化静态const成员。
至少据我所知,这有一个相当简单的原因。有一种感觉(至少部分证明)应该允许一个实现动态调整浮点精度,所以直到运行时才可能实现知道将从特定浮点生成/将要生成的确切浮点值文字。事实上,甚至有可能在执行期间发生变化。
此功能确实存在于真实硬件中。例如,Intel x86在浮点控制寄存器中有几个位,用于控制浮点计算的精度。默认情况下,计算是在80位长双精度类型上完成的,并且根据请求仅舍入到64位双精度或32位浮点数。寄存器中的这些位可以在执行期间修改,因此(例如)“1.23”在一个地方可以将变量初始化为一个值,而在程序的另一部分中的“1.23”(在调整精度之后)可能会导致(稍微)不同的值。
至少据我所知,至少在大多数典型的机器上,这仍然是理论上的可能性。尽管英特尔硬件允许动态调整FP精度,但我不知道在翻译FP文字时尝试将这种调整考虑在内的任何编译器(甚至不是英特尔)(尽管英特尔的编译器至少支持80位长)双重型)。
答案 7 :(得分:0)
正如其他人所指出的那样,在某些情况下你的编译器会被破坏。但我从来没有真正理解为什么它不允许浮点类型,除了“标准这样说”。似乎没有好的技术原因。