I'm using codepad.org
class a {
private:
const unsigned long b = 100;
};
Line 3: error: ISO C++ forbids initialization of member 'b'
compilation terminated due to -Wfatal-errors.
Sorry if I've missed something obvious, but what could be wrong?
Before C++11, you can only initialise a static const data member in the class definition:
static const unsigned long b = 100;
This is usually what you want anyway. It doesn't make much sense to have all instances of a have this constant value duplicated among them.
If you enable C++11 support, your code will compile.
In-class initialization is only allowed for static const integral types in C++03, and your variable isn't static.
Either make it static (in this case, you should - note that you also have to define it in this casee), or use a C++11 compiler.
Related
I'm working with with MS Visual Studio 2017, V. 15.9.8.
I am using the excellent JetBrains ReSharper Ultimate 2019.1.2 Build 191.0.20190603.142841. It gives me a warning at the indicated location:
#include <vector>
struct T
{
std::vector<char> m;
const char *f() const
{
static const char emptyData; // ReSharper complains here
return m.size() ? &m[0] : &emptyData;
}
};
The message is
file.h: Static local variable of type 'const unsigned char' should be initialized. This is non-standard Microsoft C++ extension.
The warning disappears if emptyData is not const.
The warning is wrong since all static data, including constant static locals, are per the standard zero-initialized, right?
The warning is wrong since all static data, including constant static locals, are per the standard zero-initialized, right?
It's just slightly inaccurate. There is initial zero initialisation indeed, but after that the variable is default initialised. For char, default initialisation is no initialisation which in case of previous zero initialisation would leave the zero value intact. A pedantically correct message would be that constant objects (of this type) must not be default initialised.
The standard (latest draft says):
If a program calls for the default-initialization of an object of a const-qualified type T, T shall be a const-default-constructible class type or array thereof.
The program violates this rule and is ill-formed.
Note that until C++17 default initialisation was not allowed for any const qualified type.
I believe it's because of the const, constants variables must be initilized, if the line is const char emptyData;, you get an error for uninitialized constvariable, so I think it's not the static modifier that is causing the problem.
There is a topic about this matter that seems interesting here.
Whether it is const static char emptyData; or static const char emptyData; the error in g++2a(GNU) compiler is:
error: uninitialized 'const emptyData' [-fpermissive]
A structure C defined several static const members like this:
Code is like below:
#include<stdio.h>
struct C{
static int i;
static const int j=1;
static constexpr double d=1;
static const double d1=1.0;
};
int main(){
return 0;
}
Compilation will lead to error:
$g++ testStatic.cpp -std=c++11
testStatic.cpp:6:25: error: in-class initializer for static data member of
type 'const double' requires 'constexpr' specifier
[-Wstatic-float-init]
static const double d1=1.0;
^ ~~~
testStatic.cpp:6:5: note: add 'constexpr'
static const double d1=1.0;
^
constexpr
1 error generated.
Why so weird
Why static int can be const,double should be constexpr,what's the rational
const follows the original language specification defined in C++98 and C++03. It was generally disallowed to supply an in-class initalizers for static const members in C++98. The possibility to do so for static const objects of integral and enum types in C++98 was part of special treatment given to these types.
constexpris a new feature introduced in C++11. It is designed differently and works uniformly for all types.
So, you can just use constexpr for both integer and floating point types and forget about any non-uniformities.
If you continue to use const in such contexts, you will have to deal with C++98 legacy. However, C++17 will introduce inline variables, which should also make it possible to use in-class initializers for inline static const objects of any type.
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 );
}
};
This is probably a ridiculously easy question, but I've been searching around for the answer for a while yet can't seem to figure this out. I'm trying to initialize a constant variable constant pointer in a class. Here is the header file:
class Scheduler{
public:
Scheduler();
explicit Scheduler( unsigned long * );
private:
const unsigned long *const thresh;
};
And here is the constructor for the class
Scheduler::Scheduler( unsigned long * threshold ):
thresh(threshold)
{}
When I attempt to compile this code I run into this error:
scheduler.cpp: In constructor ‘Scheduler::Scheduler()’:
scheduler.cpp:3: error: uninitialized member ‘Scheduler::thresh’ with ‘const’ type ‘const long unsigned int* const’
Multiple sources online discussing constant member variables in constructors for member variables point to using initializer lists. I think I'm doing what I'm supposed to, but apparently it's still no good. Can anyone see what's wrong?
You must initialize your constant member in the initialization list of ALL constructors. You are doing it only for the one with an argument. Do it for the default one too, and everything will be fne. In this particular case, either initialize your thresh with 0, or disable the default constructor.
The problem is in the default constructor, it should be
Scheduler::Scheduler() : thresh(0) {}
or not be implemented at all.
Your code works for me (MSVC2010) - as I believe it should. What compiler are you trying this with?
The only complaint a compiler may/should have with the code is a warning that the automatic copy constructor and assignment operator cannot be created because of the const member.