How to assign const static with an incremental macro? - c++

I am trying to assign an unique value to const static unsigned int members, without having to think about assigning the right values myself (preventing human errors). I've created a minimal solution for static unsigned int members, but I would really like to use const instead, because it's faster (and neat).
This is what I came up with:
// cat.h
#define ANIMAL_INDEX 0
#define GET_ANIMAL_INDEX (ANIMAL_INDEX (ANIMAL_INDEX + 1))
class Cat
{
protected:
Cat(){}
public:
const static unsigned int lynx = GET_ANIMAL_INDEX; // 0
const static unsigned int tiger = GET_ANIMAL_INDEX; // 1
};
This is just an example, but imagine that I would have like 1000 animals or something.
Is it possible to create a macro that increments every time it is used for assignment, or do I need to create a script which generates the cat.h?

If you're happy to move the definitions of your constants outside of their class, then a simple static function based implementation solves your problem:
class UniqueIndex
{
public:
static int getNext()
{
static int theIndex = 0;
return theIndex++;
}
};
class Cat
{
protected:
Cat(){}
public:
const static unsigned int lynx;
const static unsigned int tiger;
};
const unsigned int Cat::lynx = UniqueIndex::getNext();
const unsigned int Cat::tiger = UniqueIndex::getNext();
int main()
{
std::cout << Cat::lynx << ' ' << Cat::tiger << std::endl; //output: 0 1
return 0;
}

Disregarding how questionable a design this might be, an automatic counter can be useful in many cases, so here goes...
Add an abstraction around the "index" and let that handle the counting.
Then your members can be instances of this "indexing type" instead.
Something like this:
class Index
{
public:
Index() : idx(next()) {}
Index(const Index&) = delete;
Index& operator=(const Index&) = delete;
operator int () const { return idx; }
private:
const int idx;
// Avoid the "static initialization order fiasco".
static int next() { static int i = 0; return i++;}
};
struct A
{
const static Index idx;
};
const Index A::idx;
struct B
{
const static Index idx;
const static Index idx2;
};
const Index B::idx;
const Index B::idx2;
int main()
{
cout << A::idx << " " << B::idx << " " << B::idx2 << endl;
}

Related

Initialize const multidimensional array in class initializer list from constructor arguments

I have a class that includes a const 2d array of values, and I want to define this array when I call the constructor. I have been told using const on values that should never be changed is preferred, so I wanted to try it in this case.
class A {
public:
A(const int passedArray[2][2]) : memberArray(passedArray) {}
private:
const int memberArray[2][2];
};
const int passedArray[][2] = {
{0,0},
{0,1}
};
A a(passedArray); // fails with "incompatible types
//in assignment of 'const int (*)[2]' to 'const in[2][2]'
A a(&passedArray); // fails
This also fails with const int passedArray[2][2] = ..., with private: const int** memberArray, etc.
I know I have to use an initializer list because a constructor cannot change values of const. Is this possible at all on C++11?
Comments to your question has some good info.
After that here is the working code:
//g++ 5.4.0
#include <iostream>
class A {
public:
A(int passedArray[2][2])
{
//USE STD COPY TO COPY THE ARRAYS.
std::copy(&passedArray[0][0], &passedArray[0][0]+4,&memberArray[0][0]);
//PRINT VALUES TO TEST
for (int i = 0; i < 2; i++)
{
for (int j = 0; j < 2; j++)
{
std::cout << memberArray[i][j] << std::endl;
}
}
}
private:
int memberArray[2][2];
};
int main()
{
//INITIALIZE YOUR ARRAY
int passedArray[2][2] = {
{0,0},
{0,1}
};
//CREATE OBJECT
A a(passedArray);
}
If your business need is to have a "const multi dimensional array in your class"
you have to do it any one of the below ways.
class A {
public:
A(const int passedArray[2][2])
{
}
private:
const int memberArray[2][2] = {{5,6},{7,8}}; //INITIALIZE HERE
};
OR
class A {
public:
A(const int passedArray[2][2])
{
}
private:
//DECLARE STATIC HERE
static const int memberArray[2][2];
};
//INTIALIZE HERE
const int A::memberArray[2][2] = {{5,6},{7,8}};

C++ type casting alternative to virtual methods

In C++ you can use virtual methods to have following code work as you expect:
#include <iostream>
#include <string>
class BaseClass {
public:
virtual std::string class_name() const { return "Base Class"; }
};
class FirstClass : public BaseClass {
int value = 1;
public:
std::string class_name() const { return "FirstClass"; }
};
class SecondClass : public BaseClass {
long long value = -1;
public:
std::string class_name() const { return "SecondClass"; }
};
int main() {
const int array_size = 5;
const bool in_first_mode = true;
void *data;
int sample_size;
if (in_first_mode) {
data = new FirstClass[array_size];
sample_size = sizeof(FirstClass);
} else {
data = new SecondClass[array_size];
sample_size = sizeof(SecondClass);
}
// this is class-independent code
for (int index = 0; index < array_size; ++index) {
BaseClass *pointer = static_cast<BaseClass*>(data + index * sample_size);
std::cout << pointer->class_name() << std::endl;
}
return 0;
}
This will work correctly for both in_first_mode = true and in_first_mode = false.
So, basically, when you want to write code that works for both classes you can just use pointer to the BaseClass.
But what if you already given data buffer, filled with data of type TypeOne, TypeTwo, TypeThree or TypeFour, and in runtime you know that type, which stored in int type. Problem is that TypeOne, TypeTwo, TypeThree and TypeFour have not inherited from one base class. In my case, actually, they are structs from 3rd party library, which is already compiled C-compatible library, so I can not modify it. I want to get something like pointer from the example above, but problem arises with identifying what C++ type should have this pointer.
It there a more elegant type-casting alternative to making C++ class wrappers to these four types (which gives something similar to the example above), and to making pointer be void * and necessity of
if (type == 1) {
TypeOne *type_one_pointer = static_cast<TypeOne*>(pointer);
// do something
} else if (type == 2) {
/* ... */
}
every time I use pointer?
If the classes are unrelated, you can store them in a std::variant (or use Boost.Variant if your compiler is not C++17 compliant) and access the value with a visitor. This is more flexible than templates, as it allows you to include types with a different interface in the variant type.
For example (I did not compile this code):
#include <iostream>
#include <string>
#include <variant>
#include <vector>
struct TypeOne {
std::string class_name() const { return "Type one"; }
};
struct TypeTwo {
int value = 1;
std::string class_name() const { return "Type two"; }
};
struct TypeThree {
long long value = -1;
// note the different function signature
static std::string class_name() { return "Type three"; }
};
struct TypeFour {
std::string getMyClassName() const { return "Type four"; }
};
struct Visitor {
template <class T>
void operator ()(T&& value) const {
std::cout << value.class_name() << std::endl;
}
// special case
void operator ()(const TypeFour& value) const {
std::cout << value.getMyClassName() << std::endl;
}
};
int main() {
typedef std::variant<TypeOne, TypeTwo, TypeThree, TypeFour> Variant;
std::vector<Variant> values;
values.emplace_back(TypeOne{});
values.emplace_back(TypeTwo{});
values.emplace_back(TypeThree{});
values.emplace_back(TypeFour{});
for (const auto& var : values) {
std::visit(Visitor{}, var);
}
}
Thanks to #ForEveR, I find the solution. I need to use templates.
It means that if in the example above FirstClass and SecondClass would have no BaseClass one can do so:
#include <iostream>
#include <string>
class FirstClass {
int value = 1;
public:
std::string class_name() const { return "FirstClass"; }
};
class SecondClass {
long long value = -1;
public:
std::string class_name() const { return "SecondClass"; }
};
template <typename T>
void do_my_stuff(void* void_pointer) {
T *pointer = static_cast<T*>(void_pointer);
std::cout << pointer->class_name() << std::endl;
}
int main() {
const int array_size = 5;
const bool in_first_mode = true;
void *data;
int sample_size;
if (in_first_mode) {
data = new FirstClass[array_size];
sample_size = sizeof(FirstClass);
} else {
data = new SecondClass[array_size];
sample_size = sizeof(SecondClass);
}
for (int index = 0; index < array_size; ++index) {
if (in_first_mode) {
do_my_stuff<FirstClass>(data + index * sample_size);
} else {
do_my_stuff<SecondClass>(data + index * sample_size);
}
}
return 0;
}

Better way to initialize a "static const"-type variable member of a class in the main [duplicate]

This question already has answers here:
Can I initialize a static const member at run-time in C++?
(11 answers)
Closed 7 years ago.
I have a class that needs a static const variable member. The value for that class will be known at runtime by a user input. I have read a lot of post but so far none of the solution works. I am aware that this post:
Can I initialize a static const member at run-time in C++?
contains a work around, but it uses a global variable that I'd like to avoid. And also it doesn't really solve the problem.
Consider this:
#include
class A {
friend void foo(int);
static int dummy;
public:
static const int &T;
};
const int &A::T = A::dummy;
int A::dummy = 0;
void foo(int val) { A::dummy = val; }
int main() {
foo(10);
std::cout << A::T << std::endl;
foo(12);
std::cout << A::T << std::endl;
}
The program will compile and write 10 and 12 in the console. Wich defeats the purpose of the const qualifier. What is const here is the reference not the value. So I have come to the conclusion that it is not possible to have a static const class variable at execution time!
I know another way involving creating a setting-type class but it is not very neat.
So if someone knows a simple solution, please let us know!
If you don't like the global variables you could do the following scheme:
class A {
friend void foo(int);
static int dummy;
public:
static const int &T;
};
const int &A::T = A::dummy;
int A::dummy = 0;
void foo(int val) { A::dummy = val; }
int main() {
foo(10);
std::cout << A::T << std::endl;
}
Live Demo
That is declare a helper static int variable as private in your class. Make a friend a function that alters the value of that helper.
If you want to initialize it only once you can change the helper function to:
void foo(int val) {
static int count = 0;
if(!count) A::dummy = val;
++count;
}
Live Demo
Or if you don't like global functions you can make the foo function shown above a static member function of A as below:
class A {
static int dummy;
public:
static const int &T;
static void foo(int val) { A::dummy = val; }
};
const int &A::T = A::dummy;
int A::dummy = 0;
int main() {
A::foo(10);
std::cout << A::T << std::endl;
}
Live Demo
There is also something wrong with the solutions that I provided in the link of my original question and in the other solution I got. Consider this:
#include
class A {
friend void foo(int);
static int dummy;
public:
static const int &T;
};
const int &A::T = A::dummy;
int A::dummy = 0;
void foo(int val) { A::dummy = val; }
int main() {
foo(10);
std::cout << A::T << std::endl;
foo(12);
std::cout << A::T << std::endl;
}
The program will compile and write 10 and 12 in the console. Wich defeats the purpose of the const qualifier. What is const here is the reference not the value. So I have come to the conclusion that it is not possible the have a static const class variable at execution time!

Const and non-const c++ constructor

Is there a way in C++03 (or earlier) to write a class that can either store a const or non-const pointer, and handles access appropriately? Take the usage of the non-functional "SometimesConst" class as an example:
class SometimesConst
{
public:
SometimesConst(int * buffer) : buffer(buffer) {} // Needs const qualifier?
int* get() { return buffer; } // Needs const qualifier?
void increment() { counter++; }
private:
int * buffer; // Needs const qualifier?
int counter;
};
void function(int * n, const int * c)
{
// These are both okay
SometimesConst wn(n);
SometimesConst wc(c);
// Reading the value is always allowed
printf("%d %d", wn.get()[0], wc.get()[0]);
// Can increment either object's counter
wn.increment();
wc.increment();
// Can set non-const pointer
wn.get()[0] = 5;
// Should generate a compiler error
wc.get()[0] = 5;
}
Creating a const SometimesConst would not allow modification of the counter property of the object. Can a class be designed that has compile-time const safety for input objects, only if they are passed in as const?
No, not the way you are wanting to use it. The only way to have different behavior at compile time is to have different types. However, you can make that fairly easy to use:
#include <stdio.h>
template <typename T>
class SometimesConst
{
public:
SometimesConst(T* buffer) : buffer(buffer) { }
T* get() { return buffer; }
void increment() { ++counter; }
private:
T *buffer;
int counter;
};
typedef SometimesConst<const int> IsConst;
typedef SometimesConst<int> IsNotConst;
void function(int * n, const int * c)
{
IsNotConst wn(n);
IsConst wc(c);
// Reading the value is always allowed
printf("%d %d", wn.get()[0], wc.get()[0]);
// Can increment either object's counter
wn.increment();
wc.increment();
// Can set non-const pointer
wn.get()[0] = 5;
// Should generate a compiler error
wc.get()[0] = 5;
}
The language already mostly lets you do this with a simple class; with the way const cascades to access to members (combined with mutable for the counter member, which you've indicated should always be mutable), you can provide both read-only and read-write access to a buffer quite easily:
class C
{
public:
C(int* buffer) : buffer(buffer) {}
const int* get() const { return buffer; }
int* get() { return buffer; }
void increment() const { counter++; }
private:
int* buffer;
mutable int counter;
};
void function(int* n)
{
// These are both okay
C wn(n);
const C wc(n);
// Reading the value is always allowed
printf("%d %d", wn.get()[0], wc.get()[0]);
// Can increment either object's counter
wn.increment();
wc.increment();
// Can set non-const pointer
wn.get()[0] = 5;
// Generates a compiler error
wc.get()[0] = 5;
}
What you can't do with this is neatly arrange for the class to be instantiated with either a int* or a const int*; the two lead to totally different semantics for your class, so you should split it into two if you really need that.
Fortunately, templates make this easy:
template <typename T>
class C
{
public:
C(T* buffer) : buffer(buffer) {}
const T* get() const { return buffer; }
T* get() { return buffer; }
void increment() const { counter++; }
private:
T* buffer;
mutable int counter;
};
Now a C<int> is as above, but a C<const int> only provides read-only access to the buffer, even when the C<const int> object itself is not marked as const:
void function(int* n1, const int* n2)
{
C<int> a(n1);
C<const int> b(n2);
const C<int> c(n1);
const C<const int> d(n2);
// Reading the value is always allowed
printf("%d %d %d %d",
a.get()[0], b.get()[0],
c.get()[0], d.get()[0]
);
// Incrementing the counter is always allowed
a.increment();
b.increment();
c.increment();
d.increment();
// Can set non-const pointer
a.get()[0] = 5;
// Cannot set const pointer, or const/non-const pointer behind const object
//b.get()[0] = 5;
//c.get()[0] = 5;
//d.get()[0] = 5;
}
Live demo
I think that there is a design problem if you want to store two different things which must be handled in different ways in one class. But yes, you can do it:
struct X{};
class A
{
public:
A(const X*) { cout << "const" << endl; }
A(X*) { cout << "non const" << endl; }
};
int main()
{
const X x1;
X x2;
A a1(&x1);
A a2(&x2);
}
the output is expected:
const
non const

C++ : Initializing base class constant static variable with different value in derived class?

I have a base class A with a constant static variable a. I need that instances of class B have a different value for the static variable a. How could this be achieved, preferably with static initialization ?
class A {
public:
static const int a;
};
const int A::a = 1;
class B : public A {
// ???
// How to set *a* to a value specific to instances of class B ?
};
You can't. There is one instance of the static variable that is shared by all derived classes.
Static members are unique in the application. There is a single A::a constant in your system. What you can do is create a B::a static constant in B that will hide the A::a static (if you don't use the fully qualified name:
class A {
public:
static const int a = 10;
};
static const int A::a;
class B : public A {
public:
static const int a = 20;
static void test();
};
static const int B::a;
void B::test() {
std::cout << a << std::endl; // 20: B::a hides A::a
std::cout << A::a << std::endl; // 10: fully qualified
}
You can do this with Curiously recurring template pattern (you'll have to lose the const though).
template <typename T>
class A {
public:
static int a;
};
template <typename T>
int A<T>::a = 0;
class B : public A<B> {
struct helper { // change the value for A<B>::a
helper() { A<B>::a = 42; }
};
static helper h;
};
B::helper B::h;
May be we can try this way as below ::
The benefit of the below is that you don't have to write the code multiple times, but the actual generated code might be big.
#include <iostream>
using namespace std;
template <int t>
class Fighters {
protected :
static const double Fattack;
double Fhealth;
static const double Fdamage;
static int count;
public :
Fighters(double Fh) : Fhealth(Fh) { }
void FighterAttacked(double damage) {
Fhealth -= damage;
}
double getHealth()
{
return Fhealth;
}
static int getCount()
{
//cout << count << endl;
return count;
}
};
const double Fighters<1>::Fdamage = 200.0f;
const double Fighters<1>::Fattack = 0.6f;
int Fighters<1>::count = 0;
class Humans : public Fighters<1> {
public :
Humans(double Fh = 250) : Fighters<1>(Fh) { count++; }
};
const double Fighters<2>::Fdamage = 40.0f;
const double Fighters<2>::Fattack = 0.4f;
int Fighters<2>::count = 0;
class Skeletons : public Fighters<2> {
public :
Skeletons(double Fh = 50) : Fighters<2>(Fh) { count++; }
};
int main()
{
Humans h[100];
Skeletons s[300];
cout << Humans::getCount() << endl;
cout << Skeletons::getCount() << endl;
return 0;
}
This is part of my other code example .. don't mind many other data but concept can be seen.