Which function is used to initialize the static class member? - c++

I have a question about which function is chosen to init a static class member.
//Base.h
class Base
{
private:
static int count;
static int countInit()
{
return 10;
}
public:
Base()
{
}
};
//and Base.cpp
static int countInit()
{
return 0;
}
int Base::count=countInit();//member function is used.
static int local_count=countInit();//the local one in Base.cpp
The variable Base::count is initialized with Base::countInit() rather than the countInit() defined in Base.cpp. But the local_count is initialized by the local countInit. So, I wonder, is there a rule like Koenig lookup within this case?

After you write int Base::count you are in class Base, so static function of class will be called. Unqualified lookup will be used here
from 3.4.2/13
A name used in the definition of a static data member of class X (9.4.2) (after the qualified-id of the static
member) is looked up as if the name was used in a member function of X.
from 9.4.2
The definition for a static data member shall appear in a namespace
scope enclosing the member’s class definition. In the definition at namespace scope, the name of the static
data member shall be qualified by its class name using the :: operator. The initializer expression in the
definition of a static data member is in the scope of its class
Example:
class process {
static process* run_chain;
static process* running;
};
process* process::running = get_main();
process* process::run_chain = running;

Related

C++ static class member with private constructor

Why can a private constructor be used in this case? I can't explain it to myself. In this case, I initialize the class field (the type of which is the same class) from the outside, since it is static.
Edit1:
I use C++ 17 (gcc 11.2).
#include <iostream>
using namespace std;
class MainMenu {
public:
MainMenu(const MainMenu& other) = delete;
MainMenu& operator=(const MainMenu& other) = delete;
static MainMenu& GetInstance() { return _instance; }
private:
static MainMenu _instance;
MainMenu() { cout << __PRETTY_FUNCTION__ << endl;}
};
// HERE HERE HERE!!
MainMenu MainMenu::_instance = MainMenu(); // Or just MainMenu MainMenu::_instance;
int main() {
MainMenu::GetInstance();
return 0;
}
Result:
MainMenu::MainMenu()
Process finished with exit code 0
I would use the following mental model for it:
a. Note that your are instantiating the variable (it would have an incomplete type at the class's scope, so it cannot be inline withing the class's scope), not actually (re)assigning it
b. it is already declared global/static on class's scope so technically the constructor is called within the class. That's fine, even with the constructor being private, because it's called from exactly that privately accessible scope. True, the definition outside looks off, but that does not matter, as the declaration specifies its scope.
Excerpt from C++17 standard:
12.2.3.2 Static data members [class.static.data]
2 The declaration of a non-inline static data member in its class definition is not a
definition and may be of an incomplete type other than cv void. The
definition for a static data member that is not defined inline in the
class definition shall appear in a namespace scope enclosing the
member’s class definition. In the definition at namespace scope, the
name of the static data member shall be qualified by its class name
using the :: operator. The initializer expression in the definition of
a static data member is in the scope of its class (6.3.7)
And the example is your case exactly:
class process {
static process* run_chain;
static process* running;
};
process* process::running = get_main();
process* process::run_chain = running;
Any additional citations from the C++ standard to explain it in a better way are most welcome. :)

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.

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;

static keyword inside a class and outside it

The static keyword is related to internal linkage generally, but the static keyword used inside a class has external linkage right? The variables m, n below are accessible outside the class file.
class c {
int i;
int j;
static int m;
static int n;
public:
void zap();
static void clear();
};
Right.
The keyword static is heavily overloaded with too many different meanings:
On a variable or function at namespace scope it gives the name internal linkage.
On a class member it makes it a static member, which doesn't affect linkage.
On a variable at function scope it gives the variable "static storage duration" as opposed to "automatic" or "dynamic" storage duration (i.e. the variable's lifetime extends to the end of the program, like global variables.)
As I stated in my comment, static members are those associated only with the class rather than individual objects.
static members belong to the class; for variables, they're accessible without an object and shared amongst instances e.g.
struct Foo {
static void *bar;
static void *fu();
}
so Foo::bar and Foo::fu are legal.
They are introduced in §9.4 of the C++03 standard;
A data or function member of a class may be declared static in a class definition, in which case it is a static member of the class.
A static member s of class X may be referred to using the qualified-id expression X::s; it is not necessary to use the class member access syntax (5.2.5) to refer to a static member. A static member may be referred to using the class member access syntax, in which case the object-expression is evaluated
class process {
public:
static void reschedule();
};
process& g();
void f()
{
process::reschedule(); // OK: no object necessary
g().reschedule(); // g() is called
}
A static member may be referred to directly in the scope of its class or in the scope of a class derived (clause 10) from its class; in this case, the static member is referred to as if a qualified-id expression was used, with the nested-name-specifier of the qualified-id naming the class scope from which the static member is referenced.
int g();
struct X {
static int g();
};
struct Y : X {
static int i;
};
int Y::i = g(); // equivalent to Y::g();
...
You could say that static members are members of the class and not any specific object instance. That is, they have the same value for all object instances.
Static member functions, while not having a value, are otherwise the same. Instead of being unique for each object instance, they can be seen as part of the class. This means that they have no this pointer and can not access non-static member variables.

How to initialize a static const member in C++?

Is it possible to initialize a static const value outside of the constructor? Can it be initialized at the same place where member declarations are found?
class A {
private:
static const int a = 4;
/*...*/
};
YES you can but only for int types.
If you want your static member to be any other type, you'll have to define it somewhere in a cpp file.
class A{
private:
static const int a = 4; // valid
static const std::string t ; // can't be initialized here
...
...
};
// in a cpp file where the static variable will exist
const std::string A::t = "this way it works";
Also, note that this rule have been removed in C++11, now (with a compiler providing the feature) you can initialize what you want directly in the class member declaration.
Static data members (C++ only)
The declaration of a static data member in the member list of a class is not a definition. You must define the static member outside of the class declaration, in namespace scope. For example:
class X
{
public:
static int i;
};
int X::i = 0; // definition outside class declaration
Once you define a static data member, it exists even though no objects of the static data member's class exist. In the above example, no objects of class X exist even though the static data member X::i has been defined.
Static data members of a class in namespace scope have external linkage. The initializer for a static data member is in the scope of the class declaring the member.
A static data member can be of any type except for void or void qualified with const or volatile. You cannot declare a static data member as mutable.
You can only have one definition of a static member in a program. Unnamed classes, classes contained within unnamed classes, and local classes cannot have static data members.
Static data members and their initializers can access other static private and protected members of their class. The following example shows how you can initialize static members using other static members, even though these members are private:
class C {
static int i;
static int j;
static int k;
static int l;
static int m;
static int n;
static int p;
static int q;
static int r;
static int s;
static int f() { return 0; }
int a;
public:
C() { a = 0; }
};
C c;
int C::i = C::f(); // initialize with static member function
int C::j = C::i; // initialize with another static data member
int C::k = c.f(); // initialize with member function from an object
int C::l = c.j; // initialize with data member from an object
int C::s = c.a; // initialize with nonstatic data member
int C::r = 1; // initialize with a constant value
class Y : private C {} y;
int C::m = Y::f();
int C::n = Y::r;
int C::p = y.r; // error
int C::q = y.f(); // error
The initializations of C::p and C::q cause errors because y is an object of a class that is derived privately from C, and its members are not accessible to members of C.
If a static data member is of const integral or const enumeration type, you may specify a constant initializer in the static data member's declaration. This constant initializer must be an integral constant expression. Note that the constant initializer is not a definition. You still need to define the static member in an enclosing namespace. The following example demonstrates this:
#include <iostream>
using namespace std;
struct X {
static const int a = 76;
};
const int X::a;
int main() {
cout << X::a << endl;
}
The tokens = 76 at the end of the declaration of static data member a is a constant initializer.
Just for the sake of completeness, I am adding about the static template member variables.
template<class T> struct X{
static T x;
};
template<class T> T X<T>::x = T();
int main(){
X<int> x;
}
You cannot initialize static members within constructors. Integral types you can initialize inline at their declaration. Other static members must be defined (in a .cpp) file:
// .h
class A{
private:
static const int a = 4;
static const foo bar;
...
...
};
// .cpp
const foo A::bar = ...;