Why does negating a static member variable produce a linker error? - c++

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;

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 const double initialization in 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.

Definition of the static data member

I'm reading Scott Meyers' C++ and come across this example:
class GamePlayer{
private:
static const int NumTurns = 5;
int scores[NumTurns];
// ...
};
What you see above is a declaration for NumTurns, not a definition.
Why not a definition? It looks like we initialize the static data member with 5.
I just don't understand what it means to declare but not define a variable with the value 5. We can take the address of the variable fine.
class A
{
public:
void foo(){ const int * p = &a; }
private:
static const int a = 1;
};
int main ()
{
A a;
a.foo();
}
DEMO
Because it isn't a definition. Static data members must be defined outside the class definition.
[class.static.data] / 2
The declaration of a static data member in its class definition is not
a definition and may be of an incomplete type other than cv-qualified
void. The definition for a static data member shall appear in a
namespace scope enclosing the member’s class definition.
As for taking the address of your static member without actually defining it, it will compile, but it shouldn't link.
you need to put a definition of NumTurns in source file, like
const int GamePlayer::NumTurns;

definition of static const outside the class definition

Should we define a static const member outside of the class definition even if it is initialised inside the class?
#include<iostream>
using namespace std;
class abc
{
static const int period=5;
int arr[period];
public:
void display()
{
cout<<period<<endl;
}
};
const int abc::period;
int main()
{
abc a;
a.display();
return 0;
}
After commenting // const int abc::period;, both versions of the code run fine on gcc 4.3.4. So I want to ask why do both versions work and which one is standard compliant?
You are defining the static memberperiod by writing const int abc::period;. You are allowed to provide an in class initializer for static const member of a class but that's not definition, but that's merely a declaration.
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.
Your code compiles even without the definition because you are not taking the address of the static member. Bjarne Stroustrup mentions in the C++-FAQ here that You can take the address of a static member if (and only if) it has an out-of-class definition