static const float in C++. why not?
Neil Walker

Hello,
The following code has compiled fine for me. All of a sudden after using VC8 it fails. But reading up on the error it's a perfectly valid error in the C++ specs. and nothing flaky about VC. The question is, why can integers be static consts but not floats?

class SomeClass {
public:
static const int MAXVEL=10; //ok
static const float FUEL_MAX=60.0; //fails (in VC8 its C2864)
...
};

I guess the other question, is what's the best way round it?

[edit]Fixed it. Apparently I remove the initialiser from the header file:
static const float FUEL_MAX;

Then in my .cpp code add it as:
const float Car::FUEL_MAX(60.0f);

How much of a pedantic f^ck is that! c++ is just stupid sometimes. It should be either all or nothing.

CGamesPlay
class SomeClass {
public:
static const int MAXVEL=10;
static const float FUEL_MAX;
// ...
};

const float SomeClass::FUEL_MAX=60.0;

[append]
Bastard; thinking for yourself!

The reason is the same one you can't have global variables in header files. Where will it be initialized? With integers, the compiler can simply hard code the value into the program.

Neil Walker

Why can't floats be hard coded? it's just a number.

CGamesPlay

To you, maybe, but to the processor, it's more complex. Floats aren't quite as complex as objects, but they still have separate instructions for dealing with them (for instance, one can increment (add 1 to) an integer, short, or char, but you can't do that to a float).

Neil Walker

Cheers. Now I know :)

In the previous version of visual studio (2003) and in the version of GCC I used in devc++ the above worked ok.

[edit]
Actually, what I'm doing is going through the revisions of my code for a tutorial and this (revision 5 of 10) was the first time I added the const float. In the next version and onwards I had actually moved it as the code above mentioned, so I guess I must have upgraded to vc8 at that point and found the error!

Bob

It's a quirk of the C++ standard.

C++ Standard, Section 9.4.2.4 said:

If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constantinitializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions within its scope. The member shall still be defined in a namespace scope if it is used in the program and the namespace scope definition shall not contain an initializer.

There is no such allowance for non-integral types.

Neil Walker

Funny you should say that Bob, you're quoting the exact paragraph I found here:
http://www.thescripts.com/forum/thread263179.html

great minds must think alike ;)
(or read the same books)

Tobias Dammers
Quote:

To you, maybe, but to the processor, it's more complex. Floats aren't quite as complex as objects, but they still have separate instructions for dealing with them (for instance, one can increment (add 1 to) an integer, short, or char, but you can't do that to a float).

That, on the other hand, is a problem the compiler-maker has to deal with, not the programmer. The programmer has to deal with the quirk Bob describes, which is kind of a nice gesture towards compiler-makers.
And BTW, C++ does allow floats to be incremented; the fact that the compiler has to translate that into the appropriate instructions is a different story and has nothing to do with the problem at hand.

CGamesPlay
Quote:

That, on the other hand, is a problem the compiler-maker has to deal with, not the programmer. The programmer has to deal with the quirk Bob describes, which is kind of a nice gesture towards compiler-makers.
And BTW, C++ does allow floats to be incremented; the fact that the compiler has to translate that into the appropriate instructions is a different story and has nothing to do with the problem at hand.

You misunderstood why I was saying what I did. The reason for his problem not being in the standard may be completely arbitrary, btu in this case it isn't, and I was explaining why the decision to disallow non-integer types to be defined that was was made. The example involving increments was referring to the INC instruction, which doesn't exist for floats.

Arthur Kalliokoski

fld1; faddp st1; (assuming the stack isn't full)

Peter Wang

I still don't get it. Surely a float is just another bit pattern?

CGamesPlay
Quote:

Surely a float is just another bit pattern?

And by that logic, so is a DivX movie. The different is the amount of work the processor has to undertake to manipulate them.

Quote:

fld1; faddp st1;

inc [ptr];

Peter Wang

Fine, a float is a fixed width bit pattern. Initialising a machine word to hold the floating point representation of 1.0 should be no different to initialising it to hold a two's complement representation 1.

I'll admit, I don't know C++ very well. I thought all these were more-or-less equivalent:

#define FUEL_MAX 60.0

class SomeClass {
static const float FUEL_MAX=60.0;
}

const float SomeClass::FUEL_MAX=60.0;

What's the difference (modulo software engineering issues)?

CGamesPlay

The first is of course limited in its scope, and if I remember corrently, is a double. The second isn't valid :)

Quote:

Initialising a machine word to hold the floating point representation of 1.0 should be no different to initialising it to hold a two's complement representation 1.

But what if I want to have a static const struct and initialize it in the class? It's a fixed width bit pattern, too. Of course, it could have a constructor, so it would need to be initialized in a specific module. That's why static members need to be initialized outside the class declaration. And then where do the standard makers draw the line? They chose to do it after integers.

[append]
The reason integers are allow, I think, is that one can verbatim copy the constant value directly into the opcodes, and one can't do that with floats or any other data type.

Peter Wang

So the answer is, it's an arbitrary choice. Fine.

Bob

It is an arbitrary choice; but not totally arbitrary. What happens when you use two different compilers to compile your object files, and then link them together? Will you get the same float value on both? What about the various (potentially different) compiler switches?

You can spec around those issues with integers, but it becomes much more complicated with floats.

Peter Wang

Am I way off in thinking that integral static data members are allowed to facilitate simple inlining? I don't see why a non-inlined float value could work with an incompatible compiler... unless the linker is capable of rewriting floats from incompatible object files so they are of the right format?

[edit]
Found a partially satisfactory answer (to me) here:
http://www.thescripts.com/forum/thread141022.html

HoHo

I would think #defined constants are not 100% compatible with different compilers, as Bob said.

Arthur Kalliokoski
Quote:

a float is a fixed width bit pattern. Initialising a machine word to hold the floating point representation of 1.0 should be no different to initialising it to hold a two's complement representation 1.

IIRC 1.0 should always be the same for IEEE (except endianness), but the arbitrary number you're adding 1 to will be different. Every time it passes a power of two, the exponent increments and the mantissa moves over as you successively add ones. Same as scientific notation, 1.0e+0 + 1.0e+0 = 2.0e+0, but 1.0e+0 + 1.0e+1 = 1.1e+1.

Thread #587591. Printed from Allegro.cc