As reported in this Q&A, const static member functions are/were not available in C++. Did anything change since then (2011)?
Is there another way to have static member functions that do not modify the static members of their class?
Something like (pseudo-code):
class C
{
static int a;
public:
static void Incr() { ++a; }
static int Ret() const { return a; }
};
int C::a = 0;
I would need to call a [const] static member function from another class' const member function.
According to the current cppreference.com (page about static members), static member functions still cannot be const, because the const keyword only modifies the this pointer, which static functions obviously do not have.
So nothing seems to have changed since the answer you were referring to was written.
Did anything change since then (2011)?
Nothing changed, you still can't cv-qualify a static member function.
Is there another way to have static member functions that do not modify the static members of their class?
Not a perfect solution, but you may declare const "aliases" to static data members:
static int Ret() {
static constexpr const auto& a = C::a;
// Now C::a is shadowed by the local a
// and the function can't modify it.
// a = 2; // ill-formed
return a * 2; // OK
}
It still requires discipline, but at least that way a compiler can catch unintended modification attempts.
Class which has only static fields and static methods doesn't deserve to be called class. It is just form of functions and global variables with fancy name spacing.
Anyway IMO it is much better to have a regular class with regular fields and methods and then instantiate it as a global variable (not very nice solution, but at least more honest where class contains only static fields and methods).
class C
{
int a;
public:
C() : a(0) {}
void Incr() { ++a; }
int Ret() const { return a; }
};
C instance;
Or use singleton pattern which I hate.
From generated code perspective there should be no difference.
Related
In C# const implies static so you can reference a public const without having to reference an instance of a class or struct. In C++ this is not the case. If you want to access a const member variable in C++ you need to first have a reference to an instance of the class. In C++ as far as I can tell making a member variable const causes its data to be either replaced with an literal value or stored in the text or data segment (depending on the compiler) of the program. So my question is, if const member variables are allocated only once for a given class (not per instance) and stored in an area separate from instance specific member data, why can't you access a public const class member variable without a reference to an instance of the class such as:
struct Example {
const int array[] = {1, 2, 3};
};
void main() {
std::cout << Example::array[1];
}
Instead you need to make them a static const and initialize them outside of the class such as:
struct Example {
static const int array[3];
};
const int Example::array[3] = {1, 2, 3}
void main() {
std::cout << Example::array[1];
}
Just because the member is const does not imply that it has the same value in all instances. Consider:
struct foo {
const int x = 1;
foo(int a) : x(a) {}
};
foo a{1};
foo b{2};
Now a and b have different values for their const int member. I don't know C# but it looks like something is missing when you cannot have const non-static
members. On the other hand const members come with some downsides in C++ and the easiest is to avoid them completely in favor of encapsulation (when there is no setter and the member is never modified within the class, it is essentially constant).
Note that even though there is a default initializer for the member = 1; this does not imply that all instances have the same value for x. Default initializers only apply when a constructor does not provide an initializer in its member initialization list, but in the above example it does so.
So I understand that:
class Foo {
public:
static int bar;
}
Means I can access Foo::bar more or less anywhere.
But what about code like this?
class Foo {
public:
static int* bar() {
static int fred = 1;
static int barney = 2;
static int thelma = 3;
return &thelma;
}
};
How do I access fred and barney? I understand they are created only once and they exist for the lifetime of the program but presumably they aren't accessible as Foo::barney.
I have seen this pattern in real code and so wondering how it works.
There are two important concept in C++: visibility and lifetime of variables.
How do I access fred and barney? I understand they are created only once and they exist for the lifetime of the program but presumably they aren't accessible as Foo::barney.
You can't access them (not at least via their name as compiler won't be able to link them as they have no-linkage). Static variables inside your member function has visibility only inside the function; lifetime of the program (to be precise, it begins the first time the program flow encounters the declaration and it ends at program termination) and internal linkage.
static variable are used in singleton design pattern. Since, they have limited visibility but program's lifetime, that's how you can access a static variable outside the member function.
class A {
public:
A& getInstance()
{
static A self;
return self;
}
A(const A&) = delete;
A& operator=(const A&) = delete;
private:
A();
};
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;
}
What is the best way to have a static member in a non-templated library class,
without placing the burden of defining the member on the class user?
Say I want to provide this class:
class i_want_a_static_member
{
static expensive_resource static_resource_;
public:
void foo()
{
static_resource_.bar();
}
};
Then the user of the class must not forget to define the static member somewhere
(as already answered many times):
// this must be done somewhere in a translation unit
expensive_resource i_want_a_static_member::static_resource_;
I do have an answer below, but it has some disadvantages. Are there better and/or more elegant solutions?
C++17 and above
Use inline static variables for non-dynamic initialization:
struct Foo
{
inline static int I = 0;
};
And use function local static variables otherwise:
struct Foo
{
static std::string& Bar()
{
static std::string S = compute();
return S;
}
};
C++14 and below
Use function local statics, as they are plain easier to use.
If for some reason you really wish for a static data member, then you can use the template trick:
template <typename T = void>
struct Foo
{
static int I = 0; // inline initialization only for simple types.
};
template <typename T>
int Foo<T>::I;
On local statics
For resources which require dynamic initialization, it is best to use a local static.
The order in which file-scope or class-scope statics are dynamically initialized is undefined, in general, leading to the Static Initialization Order Fiasco when you try to read a uninitialized static as part of the initialization of another. Local static solve the issue by being initialized lazily, on first use.
There is some slight overhead to using local statics, however. From C++11 onwards, the initialization is required to be thread-safe, which typically means that any access is gated by an atomic read and well-predicted branch.
My own solution is to use a templated holder class, as static members work fine in templates, and use this holder as a base class.
template <typename T>
struct static_holder
{
static T static_resource_;
};
template <typename T>
T static_holder<T>::static_resource_;
Now use the holder class:
class expensive_resource { /*...*/ };
class i_want_a_static_member : private static_holder<expensive_resource>
{
public:
void foo()
{
static_resource_.bar();
}
};
But as the name of the member is specified in the holder class, you can't use the same holder for more than one static member.
As of C++ 17. You can now use inline variables to do this:
static const inline float foo = 1.25f;
Code example from http://www.learncpp.com/cpp-tutorial/812-static-member-functions/:
class Something
{
private:
static int s_nValue;
};
int Something::s_nValue = 1;
This code compiles without warnings or errors. I do not understand why.
Shouldn't we get a warning for trying to access s_nValue because it is private? Or these access specifiers do not apply to static members?
The definition of s_nValue is not "accessing" the member from outside the class--it's actually its implementation. Think of this as being just like the actual implementation of a member function, if placed in the source file outside the declaration for the enclosing class.
In other words, access specifiers absolutely apply equally to static members.
That is the definition of the private static member of the class, and therefore it is allowed. Because the definition of static members of class must go outside the class, no matter whether it is private or public.
In short, it is not accessing the member, it is defining it, just like you define private functions outside the class.
Also note: Don't get confused between Assignment and Contructors. The line:
int Something::s_nValue = 1;
Is not "assigning" a value, it's Contructing the object. In general its:
ClassA Something::s_nValue(...parameters...);
C++ allows "assignment" style syntax for Contructors. Example:
class A
{
public:
A(int i) { m_i = i; }
int getI() { return m_i; }
private:
int m_i;
};
class B
{
public:
static int getAI() { return a.getI(); }
private:
static A a;
};
A B::a = 2;