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);
}

      

+3


source to share


2 answers


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.

+1


source


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;
 }

      

0


source







All Articles