为什么“内联”?不允许使用静态常量,除了整数?
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"
,就好像它是 #定义五个“你好”
。但如果是这种情况,编译器不能在 .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
Possible Duplicate
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
};
Is there any reason for which #2, #3, #4 and #5 are illegal?
I think I know the reason for #5: the compiler needs a "real" string object (since it's not a built in type) and cannot mindlessy replace Five
with "Hello"
as if it was #define Five "Hello"
. But if that's the case, can't the compiler leave an hint in the .obj files and tell the linker to automatically create one instance of string Five
somewhere?
For #3 and #4 and especially #2 (lol!)... I can't really see any possible reason! Floats and doubles are built-in types, just as int is! And short is just a (possibly) shorter integer.
EDIT: I'm using Visual Studio 2008 to compile it. I thought all compilers behaved the same in this case, but apparently g++ compiles that fine (except #5). The errors VS gives for that snippets are:
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
int 和short 是合法的,如果你的编译器不允许它们,那么你的编译器就会崩溃:
我相信,在 C++ 标准中,浮点型和双精度型在 C++ 标准中没有像整型那样被特殊处理为常量,原因是 C++ 标准很谨慎,认为浮点型和双精度型的算术运算在不同类型上可能略有不同。编译机,而不是执行代码的机器。为了让编译器计算像 (a + b) 这样的常量表达式,它需要得到与运行时得到的相同的答案。
对于整数来说这并不是什么大问题 - 如果它不同,您可以相对便宜地模拟整数算术。但对于编译器来说,在目标设备上模拟浮点硬件可能非常困难。如果芯片有不同版本并且编译器不知道代码将在哪个版本上运行,这甚至可能是不可能的。这甚至是在你开始搞乱 IEEE 舍入模式之前。因此,标准避免了要求它,因此它不必定义编译时评估何时以及如何与运行时评估不同。
正如 Brian 提到的,C++0x 将通过 constexpr 来解决这个问题。如果我最初的动机是正确的,那么大概 10 年的时间就足以解决指定这些东西的困难。
The int and the short are legal, and if your compiler doesn't allow them then your compiler is bust:
I believe that the reason that floats and doubles aren't treated specially as constants in the C++ standard, in the way that integral types are, is that the C++ standard is wary that the arithmetic operations on float and double could be subtly different on the compiling machine, than they are on the machine that executes the code. For the compiler to evaluate a constant expression like (a + b), it needs to get the same answer that the runtime would get.
This isn't so much of an issue with ints - you can emulate integer arithmetic relatively cheaply if it differs. But for the compiler to emulate floating-point hardware on the target device might be very difficult. It might even be impossible, if there are different versions of the chip and the compiler doesn't know which the code will run on. And that's even before you start messing with the IEEE rounding mode. So the standard avoided requiring it, so that it didn't have to define when and how compile-time evaluation can differ from runtime evaluation.
As Brian mentions, C++0x is going to address this with
constexpr
. If I'm right about the original motivation, then presumably 10 years has been long enough to work through the difficulties in specifying this stuff.Example::One
和Example::Two
都应该为您编译,并且它们确实在您所说的相同环境中为我编译(VS 2008)。我不相信
Example::Three
和Example::Four
应该在标准 C++ 中编译,但我认为有一个 gcc 扩展允许它。Example::Five
不应编译。您可以在结构声明之后像这样初始化它们,通常在源文件中:
这是最可移植的方法,也是我建议的方法,即使您的编译器允许您定义
Example::Three声明中的
和Example::Four
。另一种选择是简单地从相同类型的静态函数返回值。
这个答案还讨论了可能的原因。
这个答案 讨论即将推出的 C++ 标准将如何通过 constexpr 提供帮助
Both
Example::One
andExample::Two
should compile for you, and they do indeed compile for me in the same environment you stated (VS 2008).I don't believe
Example::Three
, andExample::Four
should compile at all in standard C++, but I think there is a gcc extension that allows it.Example::Five
should not compile.You can initialize them like so after the struct declaration, typically in your source file:
This is the most portable way to do it, and the way I would recommend doing it even if your compiler allows you to define
Example::Three
andExample::Four
in your declaration.Another option would be to simply return the value from a static function of the same type.
This answer discusses a possible reason as well.
This answer discusses how the upcoming C++ standard will help via constexpr
#1 和 2 符合标准。不幸的是,有些编译器根本不符合这一要求。例如,这就是为什么 Boost 设计者必须引入诸如
BOOST_STATIC_CONSTANT
等烦人的宏来生成可移植库。如果您不想在 .cpp 文件中定义常量,可移植的解决方法是使用enum
。不过,显然在这种情况下,您无法保证类型,并且不能使用浮点数。#1 and 2 are compliant with the standard. Unfortunately, some compilers simply don't conform. That's why, for example, the Boost designers had to introduce annoying macros like
BOOST_STATIC_CONSTANT
to generate portable libraries. If you don't want to define the constant in a .cpp file, a portable workaround is to use anenum
. Although, obviously in that case you have no guarantee about the type, and you can't use floats.请参阅类内成员初始值设定项。
See In-class member initializers.
在 VS2008 下,我收到以下错误:
它很糟糕,但我想如果你的编译器也拒绝,你就不必这样做......我不知道这是一个规范问题,但我确信有人会纠正我......
Under VS2008 I get the following error:
It sucks but I guess you just have to NOT do it if your compiler refuses too ... I'm not aware of this being a spec thing but im sure someone will correct me ...
关于浮点初始值设定项,C++98 规范有这样的规定 (5.19):
Re the floating point initializers, the C++98 spec has this to say (5.19):
正如其他人所发现的,C++ 标准禁止使用浮点值初始化静态 const 成员。
至少据我了解,这有一个相当简单的原因。有一种感觉(至少部分合理),应该允许实现动态调整浮点精度,因此可能直到运行时实现才知道将从特定浮点生成的确切浮点值文字。事实上,这甚至有可能在执行过程中发生变化。
这种能力确实存在于真实的硬件中。举例来说,Intel x86 的浮点控制寄存器中有几个位用于控制浮点计算的精度。默认情况下,计算是在 80 位长双精度类型上完成的,并且仅根据请求舍入为 64 位双精度或 32 位浮点类型。寄存器中的这些位可以在执行期间修改,因此(例如)一个地方的“1.23”可以将变量初始化为一个值,而程序的另一部分(调整精度后)的“1.23”可能会导致具有(稍微)不同的值。
至少据我所知,这仍然是理论上的可能性,至少在大多数典型机器上是这样。尽管Intel硬件允许动态调整FP精度,但我不知道有任何编译器(甚至Intel的编译器)在翻译FP文字时尝试考虑这种调整(尽管Intel的编译器至少支持80位长)双型)。
As others have found, the C++ standard forbids initializing a static const member with a floating point value.
At least as I understand it, there's a fairly simple reason for this. There's a feeling (at least partially justified) that an implementation should be allowed to adjust the floating point precision dynamically, so it might not be until runtime that the implementation knows the exact floating point value that would/will be produced from a particular floating point literal. In fact, it's even possible that this could change during execution.
This capability does exist in real hardware. Just for example, the Intel x86 has a couple of bits in the floating point control register that control the accuracy of floating point calculations. By default, calculations are done on the 80-bit long double type, and only rounded to something like a 64-bit double or 32-bit float upon request. These bits in the register can be modified during execution, so (for example) "1.23" in one place could initialize a variable to one value, while "1.23" in another part of the program (after the precision had been adjusted) could result in a (slightly) different value.
At least as far as I know, this remains a theoretical possibility, at least on most typical machines. Although the Intel hardware allows dynamic adjustment of FP precision, I don't know of any compiler (not even Intel's) that attempts to take such an adjustment into account when translating FP literals (though Intel's compiler does at least support an 80-bit long double type).
正如其他人指出的那样,您的编译器在某些情况下会被破坏。但我从来没有真正理解为什么不允许浮点类型的原因,除了“标准是这么说的”。似乎没有充分的技术原因。
As others have pointed out, your compiler is broken in some cases. But I have never really understood the reason why it is not allowed for floating-point types, other than "The standard says so". There appears to be no good technical reason.