Sign in to follow this  
Justindano

Why can't static const float members be initialized in a class?

Recommended Posts

Justindano    137
Well i was just creating my particle engine in OpenGL and i thought of using classes instead of Structs, and i eventually ran into this static const float..
I never knew they could not be initialized in Class,

For ex,

[code]
class cType
{
private:
static const int Num = 10; // Ok.
static const float color = ... // Error
};
[/code]

Any reasons why?
Thanks!

Share this post


Link to post
Share on other sites
Antheus    2409
In C++ there is no meaningful difference between class and struct.

[quote]Any reasons why?[/quote]

Standard says so. There's likely obscure technical reasons for it, but there is no conspiracy of universe why it could not be done.

Share this post


Link to post
Share on other sites
Brother Bob    10344
If you don't want to separate the definition and the declaration, you can go with the function approach.
[source]
class cType
{
private:
static const int Num = 10; // Ok.
static float color() {return ... ;}
};
[/source]

Share this post


Link to post
Share on other sites
Brother Bob    10344
As Antheus said, it's because the standard says so. It simply allows for integer types only to be initialized like that, so floating point types have to be defined the normal way with separate definition in a single translation unit. At least pre-C++11...

Share this post


Link to post
Share on other sites
SiCrane    11839
No, it's because float isn't a integral or enumeration type. Under C++03 those were the only kinds of static data members you could initialize in the body of a class or struct.

Share this post


Link to post
Share on other sites
Justindano    137
And another thing, Is long-float termed as double, because i got an error message when i used long float in class initializer

[code]
static const long float num = 10.0;
Error: a member of type "const double" cannot have an in-class initializer; //Wth?
[/code]

Share this post


Link to post
Share on other sites
Brother Bob    10344
A float, whether it's long or not, is still not an integral type.

edit: Well, if I'm not mistaken, long isn't a valid modifier to the float type in the first place anyway. Your compiler probably accepts it as a language extension.

Share this post


Link to post
Share on other sites
clb    2147
[quote name='Brother Bob' timestamp='1330879737' post='4919203']
As Antheus said, it's because the standard says so. It simply allows for integer types only to be initialized like that, so floating point types have to be defined the normal way with separate definition in a single translation unit. At least pre-C++11...
[/quote]
[quote name='SiCrane' timestamp='1330879769' post='4919204']
No, it's because float isn't a integral or enumeration type. Under C++03 those were the only kinds of static data members you could initialize in the body of a class or struct.
[/quote]

Just answering 'because they say so' is not particularly insightful. Re-asking the question as 'Why does the C++03 standard state that only integral and enum static const members may be initialized inside the class body?' is more interesting to think about. What is the technical reason, if any, for the feature being only available for ints and not floats or e.g. const char * strings, so that the wording was made that way? Given the amount of work (meetings, reviews, etc.) that is (seems to be) put into producing each version of the standard, it sounds implausible that it would have just been due to oversight. Why did they choose to restrict the feature back then?

Share this post


Link to post
Share on other sites
SiCrane    11839
Nice way to take posts out of context. This is the post those were the response to:
[quote name='JustinDaniel' timestamp='1330878773' post='4919196']
Is it because float is old-school..
Because i can use
[code]
static const long color = ... //Works like a charm.
[/code]
[/quote]
The long type works because it's an integral type and float doesn't because it's not a integral or enumeration type. And if you were actually paying attention to the thread rather than locking in on random details to nitpick you'd notice that the C++11 standard does currently allow for inline literal type initialization, so there currently is no technical limitation.

However, since you seem to have all the answers here, why didn't you give the reasons? Or do you just like lecturing from a position of ignorance?

Share this post


Link to post
Share on other sites
fastcall22    10839
[quote name='JustinDaniel' timestamp='1330876575' post='4919185']
... and i eventually ran into this static const float..
I never knew they could not be initialized in Class,
[/quote]

They can be initialized in the translation unit:

[code]
// cType.h

class cType {
private:
static const int Num;
static const float color;
};


// cType.cpp
#include "cType.h"

const int cType::Num = 10;
const float cType::color = 1.f;
[/code]

Share this post


Link to post
Share on other sites
L. Spiro    25622
Floating-point values have to be initialized at run-time because of the different FPU implementations/modes.
Integral constants are always predictable. Floating-point constants change depending on the FPU rounding method currently active when the float is modified/set. It could be rounded, truncated, etc.


If they were to be initialized in the headers where the class is defined, the actual value could differ between translation units that include that header.


L. Spiro

Share this post


Link to post
Share on other sites
wqking    761
[quote name='YogurtEmperor' timestamp='1330899091' post='4919274']
Floating-point values have to be initialized at run-time because of the different FPU implementations/modes.
Integral constants are always predictable. Floating-point constants change depending on the FPU rounding method currently active when the float is modified/set. It could be rounded, truncated, etc.
[/quote]

That's quite good explanation.
I think it's also because of that that kind of constant is not a real constant. They have storage and may be changed.
That's why C++11 constexpr allows the initialization in header because they are real constants.

Share this post


Link to post
Share on other sites
SiCrane    11839
It's also an incorrect explanation. If that was the reason, then compilers like gcc wouldn't have been able to offer static const float member variables with inline definitions as extensions. And changing a variable defined as const isn't legal even if they have storage. There's nothing inherent to floating point numbers that requires them to be initialized at runtime otherwise constexpr wouldn't work with floats.

Share this post


Link to post
Share on other sites
L. Spiro    25622
It is the correct explanation. In the past compilers had no strict rules for converting floating-point values to constants. Rounding rules were not explicitly defined.

Extensions and constexpr come with explicit rules for how floating-point numbers should be converted to maintain consistency across all compilers that support those features.
IE, anything that supports the extensions is guaranteed to provide the same floating-point value, and anything that does not simply won’t compile. Hence extensions can be successful (and also why so few compilers support them).

If there was not a specifically defined method for conversion, the extension simply couldn’t be useful.


As for constexpr, it is already assumed that a lot of work will be put into a new compiler, so if the language says you have to handle floating-point conversions one way for that keyword, it is just another task to add to the stack.


L. Spiro

Share this post


Link to post
Share on other sites
SiCrane    11839
[quote name='YogurtEmperor' timestamp='1330960449' post='4919466']
It is the correct explanation.[/quote]
Source?

Share this post


Link to post
Share on other sites
wqking    761
[quote name='SiCrane' timestamp='1330985834' post='4919597']
[quote name='YogurtEmperor' timestamp='1330960449' post='4919466']
It is the correct explanation.[/quote]
Source?
[/quote]
Not reliable source, but
http://stackoverflow.com/questions/1907214/why-are-inlined-static-consts-not-allowed-except-ints
has some discussion on it.
One main opinion is that float number may have different value between the compiling machine and execute machine.

For constexpr, I believe the standard has clearly definition and restriction on it to eliminate the difference.

Share this post


Link to post
Share on other sites
SiCrane    11839
I'm looking at the C++11 standard's section on constexpr right now and it says that it's implementation defined whether or not a compile time floating point computation yields the same result as a runtime computation. In other words, the thing you're saying makes constexpr possible but static const float impossible doesn't exist.

Share this post


Link to post
Share on other sites
L. Spiro    25622
I used run-time floats as an example of how lax the standards are on how floating-point values are computed in general. Not that run-time values need to match compile-time values. That would imply that multiple floating-point modes would be forbidden under the new guidelines.

I never implied this. My second post was directed specifically at compile-time values. Basically you can’t have different compilers generating different values for the same thing. It just won’t work.
As long as compilers are required to translate the floats in a defined and consistent way, they can be compile-time constants. Otherwise they cannot. It is that simple.

Also, they are not required to match run-time derivations. That is float fVal = (2.0f/3.0f) on the compiler may not match the run-time value if truncation is involved.
However a run-time [i]copy[/i] of the compiler-generated value is guaranteed to be a match for the compile-time value.

All of this makes sense. You can’t guarantee stability without these guarantees, and that is what the extensions and the new keywords provide.
[i]The only thing that has been missing is a strict and standardized definition for what value the compiler will create when making these constants.[/i]

Think about it. What happens if a run-time float copies a compiler-generated const float, but that value is just ever so slightly different from what the compiler for that original library (containing the original float constant)? My compiler truncated. Theirs rounded up. Now my comparison of (mine >= theirs) returns false instead of true.


L. Spiro


[EDIT]
Drunken parts removed.
[/EDIT]

Share this post


Link to post
Share on other sites
SiCrane    11839
[quote name='YogurtEmperor' timestamp='1331041263' post='4919758']
[i]The only thing that has been missing is a strict and standardized definition for what value the compiler will create when making these constants.[/i]
[/quote]
[b]Which doesn't exist in the current standard.[/b] It even says the exact opposite, that the standard "imposes no restrictions on the accuracy of floating-point operations" (Section 5.19).
[quote]
You need to trust me
[/quote]
No, I don't. What was asked was the reason that the standards committee forbade inline definitions for static const floats in the previous standard. Not your supposition why they forbade it. If you can't cite an actual source then there is no reason to trust you, especially as your answer is in contradiction with what the standard actually says.

Share this post


Link to post
Share on other sites
Bregma    9202
You guys need to read "The Design and Evolution of the C++ Programming Language" by B. Stroustrup. It is enlightening. It addresses this topic with a definitive answer.

Share this post


Link to post
Share on other sites
Random question: if static const float wasn't allowed because of possible inconsistencies, why is stuff like this allowed?
[code]x = x + 93.01f;[/code]
That 93.01 could change depending on the compiler, or even the settings passed to it, and the result of the calculation can completely change depending on the processor flags (i.e. how rounding is done, etc.). So, why would this be OK, but not a named constant?

[quote name='YogurtEmperor' timestamp='1331041263' post='4919758']Think about it. What happens if a run-time float copies a compiler-generated const float, but that value is just ever so slightly different from what the compiler for that original library (containing the original float constant)? My compiler truncated. Theirs rounded up. Now my comparison of (mine >= theirs) returns false instead of true.[/quote]
This would be affected for all the same reasons I mentioned above.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this