static const double initialization in C++ - c++

I have some legacy code that I'm building with "newer" compilers and running into some static const double initialization errors that don't make sense to me. Here's what I have:
//header.h
class myclass
{
private:
static const double foo = 3.1415;
static const double bar = 12345.0 * foo;
};
When compiling this code with gcc version 4.3.3 - I am seeing the following error:
foo cannot appear in a constant-expression
I've already debunked this as not being static initialization order fiasco, as I believe intrinsic data types have a well defined order of initialization - especially when they live in the same class. As a test I've already tried to static_cast< double > the expression, but that produces yet another error stating that only integral type casts are allowed in a const expression.

static data members which are not constexpr can only be initialised directly at their declaration in the class definition if they are of integral or enumeration type. All other data types must be given a separate definition in a source file, and can only be initialised at that definition. So change your class definition to this:
class myclass
{
private:
static const double foo;
static const double bar;
};
and introduce these definitions into exactly one .cpp file:
const double myclass::foo = 3.1415;
const double myclass::bar = 12345.0 * foo;
If you have access to sufficiently modern C++, you have an alternative option of changing the in-class declarations to constexpr:
class myclass
{
private:
static constexpr double foo = 3.1415;
static constexpr double bar = 12345.0 * foo;
};
That way, they will not require a definition in a source file unless you use them as objects instead of as values (e.g. if you take their address). However, GCC 4.3.3 does not support that part of C++11.

Related

Definition of static data member without repeating its type

When I have a class with a static const or constexpr data member, defining that variable reqires me to repeat stuff:
/// my_class.hpp
class my_class { constexpr static int x = 1; };
/// my_class.cpp
#include "my_class.hpp"
// auto my_class::x; // error: declaration of 'auto my_class::x' has no initializer
// decltype(auto) my_class::x; // error: declaration of 'decltype(auto) my_class::x' has no initializer
decltype(my_class::x) my_class::x; // ok
Of course I could do
#define DEFINE_STATIC_DATA_MEMBER(x) decltype(x) x
DEFINE_STATIC_DATA_MEMBER(my_class::x);
but I wonder if there’s a non-macro solution.
The question arose because both the type and the fully-qualified name of the static data member are lengthy and I’m likely to get more of these.
Starting from C++17 you don't need to separately define static constexpr variables.
Just class my_class { constexpr static int x = 1; }; is enough, without a .cpp file.
You can make use of a typedef to not have to repeat the type when defining it.
my_class.hpp
class my_class
{
// Declaration
static const my_very_lengthy_type_name_I_dont_want_to_repeat x;
// typedef
using t = decltype(x);
};
my_class.cpp
#include "my_class.hpp"
// Initialization
my_class::t my_class::x = {};
defining that variable requires me to repeat stuff:
For static constexpr data member, the above statement is true only for Pre-C++17 standard.
From C++17 onwards, we're allowed to omit writing an out-of-class definition of a static constexpr data member. This is illustrated in the example given below.
C++11
class Foo
{
public:
static constexpr int OUT_OF_BOUNDS_VALUE = -9999; //THIS IS A DECLARATION IN C++11 and C++14
//other members here
};
In the above code snippet(which is for C++11,C++14), we have a declaration of the static data member OUT_OF_BOUNDS_VALUE inside the class. And so, in exactly one translation unit we have to provide a corresponding definition. Otherwise you'll get a linker error which can be seen here.
That is, in exactly one translation unit we should write:
constexpr int Foo::OUT_OF_BOUNDS_VALUE; //note no initializer
After adding the above out of class definition with no initializer the program will work. Demo
C++17
But the out-of-class definition for static constexpr is no longer needed from C++17 onwards.
class Foo
{
public:
static constexpr int OUT_OF_BOUNDS_VALUE = -9999; //THIS IS A DEFINITION IN C++17
//other members here
};
In the above code snippet(which is for C++17) we have a definition of the static data member OUT_OF_BOUNDS_VALUE inside the class. So since C++17, we don't have to provide the definition of OUT_OF_BOUNDS_VALUE anywhere else since we already have a definition for it inside the class and thus the same program works without any linker error.

Can I use class scope like a namespace instead of prefixing everything with the class name

So inside header files I can do
namespace X {
doThis();
}
and in the implementation file I can do
namespace X {
doThis() { .... }
}
But if I have a class
class X {
public:
doThis();
};
Is it possible for me to do something like this in the implementation file
class X {
doThis() { .... }
}
instead of X::doThis() { .... }?
There's the "Java hack"¹, where you "inherit" from the class to get its members into your namespace:
class MyUserType : /*protected|private*/ X {
void foo() {
doThis(); // works
}
}
Of course this only works of
the class doesn't define additional (non-static) features that interfere when inherited
your calling code is in a class that can inherit from the type
the derived class is not a template because 2-phase lookup makes things weird again (though you can use using declarations to mitigate them, on a name-by-name basis)
Re: static data members/out of class definition
In the comments you seem to have a problem with brevity of code mostly. Look into
Disclaimer: following examples largely copied from cppreference
inline variables (c++17), which is about namespace level static variables, which also applies to class members:
constexpr/const static member initialization right in the declaration.
If a static data member of integral or enumeration type is declared const (and not volatile), it can be initialized with an initializer in which every expression is a constant expression, right inside the class definition:
struct X
{
const static int n = 1;
const static int m{2}; // since C++11
const static int k;
};
const int X::k = 3;
constexpr members are even required to have the initializer in the declaration:
struct X {
constexpr static int arr[] = { 1, 2, 3 }; // OK
constexpr static std::complex<double> n = {1,2}; // OK
constexpr static int k; // Error: constexpr static requires an initializer
};
Note that in some circumstances you may still need out-of-class definitions, but without the initializer:
If a const non-inline (since C++17) static data member or a constexpr static data member (since C++11)(until C++17²) is odr-used, a definition at namespace scope is still required, but it cannot have an initializer. A definition may be provided even though redundant (since C++17).
struct X {
static const int n = 1;
static constexpr int m = 4;
};
const int *p = &X::n, *q = &X::m; // X::n and X::m are odr-used
const int X::n; // … so a definition is necessary
constexpr int X::m; // … (except for X::m in C++17)
¹ for the longest time Java didn't have enumerations, so you'd define static constants in a base class an "inherit" from it to get the constants.
² If a static data member is declared constexpr, it is implicitly inline and does not need to be redeclared at namespace scope. This redeclaration without an initializer (formerly required as shown above) is still permitted, but is deprecated.

Static class property, multiple constructors in C++

Say I have
class A {
public:
A();
A(int);
static const int foo;
int bar;
}
how do I go about constructing the class if I want the static member to be initialised in the constructor? This:
A::A()
{
foo = 123;
bar = 42;
}
A::A(int b)
{
foo = 123;
bar = b;
}
seems to work, but if the static member foo is shared among all the instances of the class, how is it that I can initialise it twice? It just seems like I'm doing something wrong.
Well, yes you are doing something wrong …
first off, a static const member should to be initialized directly in the class declaration (because it is const as mentioned in some comments, it can but does not 'need' to be).
But generally speaking, if you have a static class member, you can simply provide an initializer as a forward definition like so:
int A::foo = 42;
This allows the compiler to init the static member before any of your constructors are even called. (This is handled for you by the standard C++ library).
If you have a static member that is not const, you can change it anywhere you like, including "in the constructor". It may not make much sense to do so (especially in a constructor that is very strongly coupled to a given class instance), but it's possible.
If the static member is const (as in your code), you cannot change it anywhere. You can only initialize it (once). You can either do this directly with the declaration (const static int foo = 42) or in the corresponding .cpp file (const int A::foo = 42).
For C++11:
A static variable has to be defined outside the class in you cpp file, if it can't be initialized with an initializer in which every expression is a constant expression, right inside the class definition:
file.h
class A {
public:
A();
A(int);
static const int foo;
int bar;
}
file.cpp
const int A::foo = 123;
For C++17:
This can be done inlined.
class A {
public:
A();
A(int);
inline static const int foo = 123;
int bar;
}

Why does negating a static member variable produce a linker error?

Please consider the following mini example
// CFoo.hpp
class CFoo{
private:
static const double VPI = 0.5;
public:
double getVpi();
};
// CFoo.cpp
#include "CFoo.hpp"
double CFoo::getVpi(){
double x = -VPI;
return x;
}
// main.cpp
#include "CFoo.hpp"
int main(){
CFoo aFoo();
return 0;
}
Lining the program with gcc version 4.5.1 produces the error CFoo.cpp: undefined reference to CFoo::VPI. The error dose not occur if
VPI is not negated
the negation is written as double x = -1 * VPI;
Declaration and definition of class CFoo happen in the same file
Do you know the reason for this error?
There are multiple problems with your code. Primarily, this is not valid C++03:
class CFoo{
private:
static const double VPI = 0.5;
// ...
};
The declaration of a static data member can specify a constant initializer if and only if that initializer is const integral or const enumeration type. 0.5 is neither of these, and hence your code is not valid C++. 9.4.2 Static data members covers this:
2/ The declaration of a static data member in its class definition is
not a definition [...]The definition for a static data member shall
appear in a namespace scope enclosing the member’s class definition.
[...]
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 order to initialize VPI, you must do so in the CPP file:
header:
class CFoo{
private:
static const double VPI;
};
cpp :
const double CFoo::VPI = 0.5;
Another problem, unrelated, is here:
int main(){
CFoo aFoo(); // NOT OK
return 0;
The expression CFoo aFoo(); doesn't do what you think it does. You think it declares an object aFoo of type CFoo and initializes it using CFoo's default constructor. But what it actually does is declare a function named aFoo taking no parameters, returning a CFoo by value. This is known as the most vexing parse. In order to do what you want, simple omit the parenthesis:
CFoo aFoo;

Does constant static member variables of a class or a struct in C++ need not be defined separately?

Does constant static member variables of a class or a struct in C++ need not be defined separately?
Is this correct?
struct test
{
const static int x;
};
int test::x;
No that's not correct. The definition must match the declaration and x is const int, not int. As a const variable of POD type it also needs to be initialized. E.g.
const int test::x = 0;
As a const static member of integral type, it is also allowed to supply the initializer in the definition of the class instead.