C ++ Separate static field for each derived class
Over time, as we thought about solving my problem, I finally came to the conclusion that I have no other ideas but to ask here.
I have the following problem.
Short version. How can I inherit a static field from a base class, but make it unique in each derived class and still be able to match those classes to the parent class?
Long version. I need to create some kind of basic interface for a set of classes. Each of these classes must have one static field and one static method. But I want to be able to pass all of these classes as parameters to one generic function that uses these static members. So I was thinking about inheriting them all from one base class.
But of course, I cannot just inherit static members and expect them to be unique in every child class. I tried to use the Curiously Recurring Template Pattern (CRTP) but it made me make this generic function template as well and give it a class name on every call. This is not good for me.
Also I am having problems that CRTP works when more than one level of inheritance is used (i.e. when I want to get another class from a class derived from this template base class). Is there a way to achieve what I need?
I know similar questions have already been asked, but in most of them the authors were happy with CRTP. This doesn't sound like a good solution to me.
//pseudo-code for what I need, doesn't work of course
class Base {
public:
static int x;
static int GetX() {return x;}
}
class Derived : public Base {};
class NextDerived : public Derived {};
class NextDerived2 : public Derived {};
void Foo(Base& a) {a.x = 10;}
int main {
NextDerived d;
NextDerived2 d2;
Foo(d);
Foo(d2); //both Foos modify different static variables
}
//CRTP attempt
template <class C>
class Base {
public:
static int x;
static int GetX() {return x}
};
class Derived : public Base<Derived> {};
int Derived::x = 0;
template <class C>
void Foo(Base<C>& b) {
b.x = 10;
return;
};
int main() {
Derived d;
Foo<Derived>(d);
}
source to share
Be aware that static variables must be defined as well. Therefore, for each derived type that requires a separate static variable, you will need to define it as well.
Instead, you can use a std::map
type id hash to do something like this without having to clutter up your base class.Also, this allows any type to be used, for example:
#include <iostream>
#include <map>
#define out(v) std::cout << v << std::endl
static std::map<std::size_t, int> ExsAndOhs;
template < typename T >
static std::size_t type_id() // in case you don't want RTTI on
{
static char tid;
return reinterpret_cast<std::size_t>(&tid);
}
template < typename T >
void Foo(int _x) { ExsAndOhs[type_id<T>()] = _x; }
template < typename T >
void Foo(T& obj, int _x) { ExsAndOhs[type_id<T>()] = _x; }
template < typename T >
void Print() { out(ExsAndOhs[type_id<T>()]); }
template < typename T >
void Print(T& obj) { out(ExsAndOhs[type_id<T>()]); }
class Base {};
class Derived : public Base {};
class D2 : public Base {};
int main(int argc, char* argv[])
{
// using explicit templates
Foo<Base>(100);
Foo<Derived>(10);
Foo<D2>(42);
Foo<long>(65535);
Foo<int>(1955);
Print<Base>();
Print<Derived>();
Print<D2>();
Print<long>();
Print<int>();
Base b;
Derived d;
D2 d2;
int x = 1;
long y = 1;
// using template deduction
Foo(b, 10);
Foo(d, 42);
Foo(d2, 100);
Print(b);
Print(d);
Print(d2);
Print(x); // still prints 1955
Print(y); // still prints 65535
return 0;
}
It also avoids declaring all static members of derived classes.
This may not be a good solution for your specific use case, but it is an alternative that gets you what you ask for.
Hope it helps.
source to share
Does this CRTP style work for you?
#include <iostream>
using namespace std;
template<class T>
class Base {
public:
static int x;
static int GetX() {return x;}
};
template<class T>
class Derived : public Base <Derived<T> >{};
class NextDerived : public Derived<NextDerived> {};
class NextDerived2 : public Derived<NextDerived2> {};
static int count = 0;
template<class T> int Base<T>::x = 0;
template<class T>
void Foo(Base<Derived<T> >& a) {
a.x = count++;
};
int main() {
NextDerived d;
NextDerived2 d2;
Foo(d);
Foo(d2);
cout << d.GetX() << " " << d2.GetX() << endl;
return 0;
}
source to share