I've recently run into Visual C++ 2005 failing to initialize in class constants, having run into the ubiquitous error
"error C2864: ... : only static const integral data members can be initialized within a class"
from code similar to
class MyClass:
{
private:
static const double myConstant = 2.9768;
}
I've been able to figure out that non-integer types are the problem, and there are several ways to have integer constants, but I have not found a satisfactory work-around for defining constants scoped to a class. Is this type of declaration legal in later/other compilers?
In C++03, you have to initialize non-integral static constants outside the class definition:
struct Foo
{
static const double value;
};
const double Foo::value = 0.5;
In C++11, you can initialize arbitrary constexpressions from constant expressions inline:
struct Foo
{
static constexpr double value = 0.5;
};
You may or may not still have to provide a definition for the variable, depending on whether you require it elsewhere in your code (e.g. by taking its address).
Do it outside the class definition, in a source file (not a header, or you risk linker errors).
const double MyClass::myConstant = ..;
This behaviour is mandated by the C++ language standard. No legal workaround.
Take the initialization out of the header file and put this into your .cpp:
const double MyClass::myConstant = 2.9768;
Related
I have a class with static const members that I'm initializing inside the class declaration:
#include <iostream>
class Foo
{
public:
static const int i = 9;
static const float f = 2.9999;
};
int main()
{
std::cout << Foo::i << std::endl;
std::cout << Foo::f << std::endl;
return 0;
}
When compiled with GCC 4.8.2 with option --std=c++11, it gives this compile error:
foo.cpp:7:32: error: ‘constexpr’ needed for in-class initialization of static data member ‘const float Foo::f’ of non-integral type [-fpermissive]
static const float f = 2.9999;
^
As the message indicates, the error goes away if the line is changed to static constexpr float f = 2.9999;.
Why should the in-class static const initialization of a floating-point variable be any different from a integral variable? Aren't they both just a value of certain size (number of bytes) that is copied over (like a macro) or referred to using a pointer?
Some older answers to similar (not the same) questions on SO indicate that this is because floating point expressions might give different results between the compiled machine and the execution machine (assuming a cross-compilation scenario).
However:
the above code assigns a value directly, there is no arithmetic operation that needs to be performed to compute a value
there might be different results for integral expressions too since its underflow and overflow results are not unambiguously defined across different architectures.
Finally, what magic does constexpr do here that const does not? Why doesn't the language just do what constexpr does when const is used? I mean, why another keyword when the following statements work fine as C++ code outside a class anyway:
const int i = 9;
const float f = 2.9999;
It's just a limitation of the language, and one that has been addressed by the introduction of generalized constant expressions.
Since the original C++, only static class member constants of integral type can be initialized inline; this is the is same type restriction as for non-type template parameters. So you can combine the two like this:
struct MyTrait { static const int value = 10; };
template <int N> struct Foo;
Foo<MyTrait::value> foo;
In this usage, the static constant is not odr-used and no definition is required. I'm speculating, but I can imagine that this kind of use was the primary intention of allowing inline initialization. For all other types, you would presumably want to have a definition anyway, so you might as well put the initializer in the definition.
This isn't an excuse, of course, and I suppose the introduction of constexpr seeks to rectify this original narrow-mindedness.
The problem with the following code is static member of type "const double" cannot have an in-class initializer. Why is applicable only for a 'const double'in the following code? Please help me.
class sample{
static const char mc = '?';
static const double md = 2.2;
static const bool mb = true;
};
const char sample::mc;
const double sample::md;
const bool sample::mb;
int main(){
}
The logic implemented by the C++03 language standard is based on the following rationale.
In C++ an initializer is a part of object definition. What you write inside the class for static members is actually only a declaration. So, formally speaking, specifying initializers for any static members directly inside the class is "incorrect". It is contrary to the general declaration/definition concepts of the language. Whatever static data you declare inside the class has to be defined later anyway. That's where you will have your chance to specify the initializers.
An exception from this rule was made for static integer constants, because such constants in C++ can form Integral Constant Expressions (ICEs). ICEs play an important role in the language, and in order for them to work as intended the values of integral constants have to be visible in all translation units. In order to make the value of some constant visible in all translation units, it has to be visible at the point of declaration. To achieve that the language allows specifying the initializer directly in class.
Additionally, on many hardware platforms constant integer operands can be embedded directly into the machine commands. Or the constant can be completely eliminated or replaced (like, for example, multiplication by 8 can be implemented as a shift by 3). In order to facilitate generation of machine code with embedded operands and/or various arithmetical optimizations it is important to have the values of integral constants visible in all translation units.
Non-integral types do not have any functionality similar to ICE. Also, hardware platforms do not normally allow embedding non-integral operands directly into the machine commands. For this reason the above "exception from the rules" does not extend to non-integral types. It would simply achieve nothing.
The compiler offered me to use constexpr instead of const:
static_consts.cpp:3:29: error: ‘constexpr’ needed for in-class initialization of static data member ‘const double sample::md’ of non-integral type [-fpermissive]
static_consts.cpp:7:22: error: ‘constexpr’ needed for in-class initialization of static data member ‘const double sample::md’ of non-integral type [-fpermissive]
I've just accepted the offer:
class sample{
static const char mc = '?';
static constexpr double md = 2.2;
static const bool mb = true;
};
const char sample::mc;
const bool sample::mb;
int main(){
}
And now it compiles just fine (C++11).
Pre-C++11, only const integral types could be directly initialized in the class definition. It's just a restriction imposed by the standard.
With C++11, this no longer applies.
In PHP and C# the constants can be initialized as they are declared:
class Calendar3
{
const int value1 = 12;
const double value2 = 0.001;
}
I have the following C++ declaration of a functor which is used with another class to compare two math vectors:
struct equal_vec
{
bool operator() (const Vector3D& a, const Vector3D& b) const
{
Vector3D dist = b - a;
return ( dist.length2() <= tolerance );
}
static const float tolerance = 0.001;
};
This code compiled without problems with g++. Now in C++0x mode (-std=c++0x) the g++ compiler outputs an error message:
error: ‘constexpr’ needed for in-class initialization of static data member ‘tolerance’ of non-integral type
I know I can define and initialize this static const member outside of the class definition. Also, a non-static constant data member can be initialized in the initializer list of a constructor.
But is there any way to initialize a constant within class declaration just like it is possible in PHP or C#?
Update
I used static keyword just because it was possible to initialize such constants within the class declaration in g++. I just need a way to initialize a constant in a class declaration no matter if it declared as static or not.
In C++11, non-static data members, static constexpr data members, and static const data members of integral or enumeration type may be initialized in the class declaration. e.g.
struct X {
int i=5;
const float f=3.12f;
static const int j=42;
static constexpr float g=9.5f;
};
In this case, the i member of all instances of class X is initialized to 5 by the compiler-generated constructor, and the f member is initialized to 3.12. The static const data member j is initialized to 42, and the static constexpr data member g is initialized to 9.5.
Since float and double are not of integral or enumeration type, such members must either be constexpr, or non-static in order for the initializer in the class definition to be permitted.
Prior to C++11, only static const data members of integral or enumeration type could have initializers in the class definition.
Initializing static member variables other than const int types is not standard C++ prior C++11. The gcc compiler will not warn you about this (and produce useful code nonetheless) unless you specify the -pedantic option. You then should get an error similiar to:
const.cpp:3:36: error: floating-point literal cannot appear in a constant-expression
const.cpp:3:36: warning: ISO C++ forbids initialization of member constant ‘tolerance’ of non-integral type ‘const float’ [-pedantic]
The reason for this is that the C++ standard does not specifiy how floating point should be implemented and is left to the processor. To get around this and other limitations constexpr was introduced.
Yes. Just add the constexpr keyword as the error says.
I ran into real problems with this, because I need the same code to compile with differing versions of g++ (the GNU C++ compiler). So I had to use a macro to see which version of the compiler was being used, and then act accordingly, like so
#if __GNUC__ > 5
#define GNU_CONST_STATIC_FLOAT_DECLARATION constexpr
#else
#define GNU_CONST_STATIC_FLOAT_DECLARATION const
#endif
GNU_CONST_STATIC_FLOAT_DECLARATION static double yugeNum=5.0;
This will use 'const' for everything before g++ version 6.0.0 and then use 'constexpr' for g++ version 6.0.0 and above. That's a guess at the version where the change takes place, because frankly I didn't notice this until g++ version 6.2.1. To do it right you may have to look at the minor version and patch number of g++, so see
https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
for the details on the available macros.
With gnu, you could also stick with using 'const' everywhere and then compile with the -fpermissive flag, but that gives warnings and I like my stuff to compile cleanly.
Not great, because it's specific to gnu compilers, butI suspect you could do similar with other compilers.
If you only need it in the one method you can declare it locally static:
struct equal_vec
{
bool operator() (const Vector3D& a, const Vector3D& b) const
{
static const float tolerance = 0.001f;
Vector3D dist = b - a;
return ( dist.length2() <= tolerance );
}
};
I'm declaring a class which needs some public constants. My idea was declaring ones just like this:
class MyClass {
public:
const int kIntConst = 1234;
const float kFloatConst = 1234.567f;
// ...methods...
};
This approach works fine for int constant but fails for the float one with the following error:
error C2864: 'MyClass::kFloatConst' : only static const integral data members can be initialized within a class
Well, I do understand this error message. It says I cannot have a float (non-integral) constant declared in the class declaration. So, the question is: WHY!? Why it can be int but not float?
I know how to workaround this. Declaring kFloatConst as a static const member and later initialization in .cpp solves the problem but this is not what I'd like to have. I need a compile time constant (a one which can be optimized by compiler), not a constant class member which needs .obj file linking.
Using macro could be an option but macro doesn't have namespace and I don't like globally defined constants.
The general rule is that you cannot have constants defined inside the class declaration.
Then there is an exception that integral constants are allowed anyway. So the int constant isn't the rule, but the exception.
Static constants in the ios_base class are initialized when created, which makes sense for constants. Can non-constant static member variables be initialized the same way, or is this concept only allowed for constant static members?
For non-constant static members with gnu compilers must use always define/allocate space separately from it's deceleration in the header? Is it even proper to initialize constant static members this way?
Class members can be created and initialized only for the static const (integral data type, like int, char, double etc.) members in current C++ standard. For non-static member it's not possible. However, in C++0x that facility is introduced.
Edit: For non-const static member, you can do initialization but you have to do the same in .cpp file (for non template classes). e.g.
struct A
{
static const int i = 0; // ok
static int j; // can declare in .cpp file as below
int k = 2; // error, but valid in C++0x
const int l = 3; // error, valid in C++0x
static const int m[2] = {1,2}; // error, should be an integral type
static const string n = "hi"; // error, should be an integral type
};
int A::j = 1 // declare in class body, and define outside
Because static data members must be
explicitly defined in exactly one
compilation unit.
From C++ FAQ
http://www.parashift.com/c++-faq-lite/ctors.html#faq-10.12
You might want to read the whole "Constructors" section about "static data member" to clearly understand it.
http://www.parashift.com/c++-faq-lite/ctors.html