TITLE: floating point values as compile time constants (Newsgroups: comp.lang.c++.moderated, 25 Aug 97) [ class X { public: enum color { red, green, blue }; static const int i = 10; // ok static const color c = red; // ok static const double f = 1.234; // not allowed! }; ] FU: Charles Fu > >> Which brings up a question I had meant to ask some time > >> ago: why did the committee choose not to allow this > >> capability for static const floating members? CLAMAGE: Steve Clamage wrote: > > Because floating-point values cannot appear in > > constant-expressions. The reason for that is otherwise the > > compiler would have to emulate floating-point on the target > > system, which is otherwise not required. The same is true in C. FU: > I hate to disagree, but I believe both C and C++ allow > "arithmetic constant expressions" that have floating literals > (6.4 of C standard, 5.19.2-3 of my latest C++ draft). > Admittedly, their usefulness is much more limited than for > integral constant expressions, but there is some usefulness. CLAMAGE: Oops. I didn't qualify my comment correctly. There are many kinds of constant-expressions in C and C++. Let's speak loosely of "compile-time constants", a term which is not used in the C or C++ standards. Compile-time constants are used in contexts where their value is needed at compile time. Examples are determining the size of static arrays, the number of bits in a bit-field, and the value of a non-type template parameter. An interpreter could wait until "run time" to determine these values, but C and C++ are intended to make traditional compile-link-run systems useful and practical. (That is a language design criterion. Different criteria are used in other languages.) The language definition does not use the term "compile-time constants", but instead enumerates the cases that we can think of as "compile-time constants." In particular, the in-class initializer of a static data member is intended to be a compile-time constant -- otherwise why bother with this added feature? There are two problems with floating-point values as compile-time constants. First, the value may be unexpectedly different on different systems, and second (as I originally stated), the compiler would have to emulate floating-point arithmetic on the target system. (One could argue that integer arithmetic can have different results on different systems, but that shows up on overflow or other exceptional conditions. Floating-point differences are inherent in floating point and cannot be predicted. For example, whether 0.1 == 1e20/1e21 depends not only on the representation used, but on the computational method.) Problem 1 example: Suppose we allowed non-type template parameters of floating-point type: template< double V > class foo { ... }; Consider these two instantiations: foo<1.0/10.0> f1; foo<0.1> f2; The result of 1.0/10.0 might not be the same as the value of the literal 0.1. Thus, f1 and f2 might have the same type or unexpectedly different types, depending on the system. Problem 2 example: struct X { static const double c = 1.0/10.0; static const bool b = (c == 0.1); }; double x = 1.0; double y = 10.0; bool b = (x/y == 0.1); // computed at run time Variables b and X::b really ought to have the same value. To get consistent results on the same platform, the compiler would have to emulate exactly the run-time floating-point arithmetic of the target. The host and target platforms might be different. Even if they are the same, some platforms support different forms of run-time floating-point, and the compiler would have to be able to emulate all of them exactly. Nothing else in C or C++ requires that the compiler be able to emulate target floating-point, or even perform any floating-point arithmetic at all. For those reasons, floating-point values and arithmetic are excluded from constant-expressions which would be considered "compile-time constants".