I am sorry for my newbie question, but I do not know much about C++. Can anybody answer why I get the error "error: a call to a constructor cannot appear in a constant-expression" when compiling following code;
class EliminationWeight
{
public:
typedef double Type;
static const Type MAX_VALUE = __DBL_MAX__;
static const Type MIN_VALUE = -__DBL_MAX__;
};
I use Ubuntu 12.04 and gcc that comes with it. It is not my code and I know that this code probably it works OK 100% (perhaps in older version of gcc or other compiler). Is there a quick way to fix it?
Thanks in advance for any answers, this is actually my first time asking something at SO.
Call to a constructor cannot appear in a constant-expression is a GCC error message which doesn't really make sense to me here. Clang, for instance, accepts your code with some warnings:
test.cpp:31:23: warning: in-class initializer for static data member of type
'const Type' (aka 'const double') is a GNU extension [-Wgnu]
static const Type MAX_VALUE = __DBL_MAX__;
^ ~~~~~~~~~~~
Anyway, initializing double in a class body is non-standard. You should do initialization separately:
class EliminationWeight
{
public:
typedef double Type;
static const Type MAX_VALUE;
static const Type MIN_VALUE;
};
and then in exactly one source file (not a header file):
const EliminationWeight::Type EliminationWeight::MAX_VALUE = __DBL_MAX__;
const EliminationWeight::Type EliminationWeight::MIN_VALUE = -__DBL_MAX__;
In general, you can only initialize static member variables having integral types in class body, although this has been extended in C++ 0x11. See also Initializing const member within class declaration in C++
I just stumbled across this exact same problem. The code we are discussing is part of the Contraction Hierarchies implementation by KIT.
This is the only compilation error given when trying to compile the code with gcc 4.8.
The fix suggested by #vitaut is what is needed to make this work. However, note that there are already the following lines lingering in main.cpp:
// doesn't look nice, but required by the compiler (gcc 4)
...
const EliminationWeight::Type EliminationWeight::MAX_VALUE;
const EliminationWeight::Type EliminationWeight::MIN_VALUE;
If you decide to create an EliminationWeight.cpp file to go along with your EliminationWeight.h and include it in the Makefile, these lines are the reason why you are seeing a different error than mentioned above:
main.cpp:86:31: error: uninitialized const ‘EliminationWeight::MAX_VALUE’ [-fpermissive]
const EliminationWeight::Type EliminationWeight::MAX_VALUE;
^
main.cpp:87:31: error: uninitialized const ‘EliminationWeight::MIN_VALUE’ [-fpermissive]
const EliminationWeight::Type EliminationWeight::MIN_VALUE;
^
The solution is to either remove these lines in main.cpp or use them for the actual initialization. I have gone with the latter and the lines now look like this:
const EliminationWeight::Type EliminationWeight::MAX_VALUE = std::numeric_limits< EliminationWeight::Type >::max();
const EliminationWeight::Type EliminationWeight::MIN_VALUE = -std::numeric_limits< EliminationWeight::Type >::max();
Note that I have used the std::numeric_limits template for the type defined by the EliminationWeight::Type typedef. This means we only need to change that typedef to use a different type.
However, using these in main.cpp mandates that we include the header for the numeric_limits template. It also worked for me without including the header but that is probably because it is included via some other included file. For the purpose of clean code we should include it anyway.
#include <limits>
Also note that C++11 provides a new function lowest for the numeric_limits template meaning you could substitue the last line with the following:
const EliminationWeight::Type EliminationWeight::MIN_VALUE = std::numeric_limits< EliminationWeight::Type >::lowest();
However, the C++ reference on lowest specifies the return value for floating point types as
implementation-dependent; generally, the negative of max()
so I am not sure whether you gain much by using this function. It does give you cleaner looking code but it seems the return value is somewhat unspecified.
I had this problem when I was going to declare and instantiate a static const object of class Time inside a class Alg. It worked when I declare the member variable inside the class and instantiate it out side, like this:
Class Alg {
public:
.
.
static const Time genTime;
.
.
}
const Alg::genTime = Time(0,0,1,0);
Related
While writing a custom reflection library I encountered a strange compiler behavior. However I was able to reproduce the problem with a much simplified code. Here is:
#include <iostream>
class OtherBase{};
class Base{};
/* Used only as a test class to verify if the reflection API works properly*/
class Derived : Base, OtherBase
{
public:
void Printer()
{
std::cout << "Derived::Printer() has been called" << std::endl;
}
};
/*Descriptor class that basically incapsulate the address of Derived::Printer method*/
struct ClassDescriptor
{
using type = Derived;
struct FuncDescriptor
{
static constexpr const auto member_address{ &type::Printer };
};
};
int main()
{
Derived derived;
auto address{ &Derived::Printer };
(derived.*address)(); // -> OK it compiles fine using the local variable address
(derived.*ClassDescriptor::FuncDescriptor::member_address)(); // -> BROKEN using the address from the descriptor class cause fatal error C1001 !
}
While trying debugging this problem I noticed that:
It happen only if Derived has multiple inheritance.
If I swap static constexpr const auto member_address{ &type::Printer } with inline static const auto member_address{ &type::Printer } it works.
Is it just a compiler bug, or I'm doing something wrong ?
Can I solve this problem while keeping the constexpr ?
Please note that I'm using MSVC 2017 with the compiler version 19.16.27024.1
All compiler options are default except for /std:c++17 enabled.
I know that updating (and surely i'll do it) the compiler version to the last one will probably solve the issue, but for now I would like to understand more about this problem.
About C1001, Microsoft Developer Network suggests that you remove some optimizations in your code: Fatal Error C1001. Once you've worked out which optimization is causing the issue, you can use a #pragma to disable that optimization in just that area:
// Disable the optimization
#pragma optimize( "", off )
...
// Re-enable any previous optimization
#pragma optimize( "", on )
Also, a fix for this issue has been released by Microsoft. You could install the most recent release.
const and constexpr:
const declares an object as constant. This implies a guarantee that once initialized, the value of that object won't change, and the compiler can make use of this fact for optimizations. It also helps prevent the programmer from writing code that modifies objects that were not meant to be modified after initialization.
constexpr declares an object as fit for use in what the Standard calls constant expressions. But note that constexpr is not the only way to do this.
When applied to functions the basic difference is this:
const can only be used for non-static member functions, not functions in general. It gives a guarantee that the member function does not modify any of the non-static data members.
constexpr can be used with both member and non-member functions, as well as constructors. It declares the function fit for use in constant expressions. The compiler will only accept it if the function meets certain criteria (7.1.5/3,4), most importantly:
The function body must be non-virtual and extremely simple: Apart from typedefs and static asserts, only a single return statement is allowed. In the case of a constructor, only an initialization list, typedefs, and static assert are allowed. (= default and = delete are allowed, too, though.)
As of C++14, the rules are more relaxed, what is allowed since then inside a constexpr function: asm declaration, a goto statement, a statement with a label other than case and default, try-block, the definition of a variable of non-literal type, definition of a variable of static or thread storage duration, the definition of a variable for which no initialization is performed.
The arguments and the return type must be literal types (i.e., generally speaking, very simple types, typically scalars or aggregates)
When can I / should I use both, const and constexpr together?
A. In object declarations. This is never necessary when both keywords refer to the same object to be declared. constexpr implies const.
constexpr const int N = 5;
is the same as
constexpr int N = 5;
However, note that there may be situations when the keywords each refer to different parts of the declaration:
static constexpr int N = 3;
int main()
{
constexpr const int *NP = &N;
}
Here, NP is declared as an address constant-expression, i.e. a pointer that is itself a constant expression. (This is possible when the address is generated by applying the address operator to a static/global constant expression.) Here, both constexpr and const are required: constexpr always refers to the expression being declared (here NP), while const refers to int (it declares a pointer-to-const). Removing the const would render the expression illegal (because (a) a pointer to a non-const object cannot be a constant expression, and (b) &N is in-fact a pointer-to-constant).
B. In member function declarations. In C++11, constexpr implies const, while in C++14 and C++17 that is not the case. A member function declared under C++11 as
constexpr void f();
needs to be declared as
constexpr void f() const;
under C++14 in order to still be usable as a const function.
You could refer to this link for more details.
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.
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.
My understanding is that C++ allows static const members to be defined inside a class so long as it's an integer type.
Why, then, does the following code give me a linker error?
#include <algorithm>
#include <iostream>
class test
{
public:
static const int N = 10;
};
int main()
{
std::cout << test::N << "\n";
std::min(9, test::N);
}
The error I get is:
test.cpp:(.text+0x130): undefined reference to `test::N'
collect2: ld returned 1 exit status
Interestingly, if I comment out the call to std::min, the code compiles and links just fine (even though test::N is also referenced on the previous line).
Any idea as to what's going on?
My compiler is gcc 4.4 on Linux.
My understanding is that C++ allows static const members to be defined inside a class so long as it's an integer type.
You are sort of correct. You are allowed to initialize static const integrals in the class declaration but that is not a definition.
Interestingly, if I comment out the call to std::min, the code compiles and links just fine (even though test::N is also referenced on the previous line).
Any idea as to what's going on?
std::min takes its parameters by const reference. If it took them by value you'd not have this problem but since you need a reference you also need a definition.
Here's chapter/verse:
9.4.2/4 - If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions. 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.
See Chu's answer for a possible workaround.
Bjarne Stroustrup's example in his C++ FAQ suggests you are correct, and only need a definition if you take the address.
class AE {
// ...
public:
static const int c6 = 7;
static const int c7 = 31;
};
const int AE::c7; // definition
int f()
{
const int* p1 = &AE::c6; // error: c6 not an lvalue
const int* p2 = &AE::c7; // ok
// ...
}
He says "You can take the address of a static member if (and only if) it has an out-of-class definition". Which suggests it would work otherwise. Maybe your min function invokes addresses somehow behind the scenes.
Another way to do this, for integer types anyway, is to define constants as enums in the class:
class test
{
public:
enum { N = 10 };
};
Not just int's. But you can't define the value in the class declaration. If you have:
class classname
{
public:
static int const N;
}
in the .h file then you must have:
int const classname::N = 10;
in the .cpp file.
Here's another way to work around the problem:
std::min(9, int(test::N));
(I think Crazy Eddie's answer correctly describes why the problem exists.)
As of C++11 you can use:
static constexpr int N = 10;
This theoretically still requires you to define the constant in a .cpp file, but as long as you don't take the address of N it is very unlikely that any compiler implementation will produce an error ;).
C++ allows static const members to be defined inside a class
Nope, 3.1 §2 says:
A declaration is a definition unless it declares a function without specifying the function's body (8.4), it contains the extern specifier (7.1.1) or a linkage-specification (7.5) and neither an initializer nor a functionbody, it declares a static data member in a class definition (9.4), it is a class name declaration (9.1), it is an opaque-enum-declaration (7.2), or it is a typedef declaration (7.1.3), a using-declaration (7.3.3), or a using-directive (7.3.4).