Raddeo
Raddeo

Reputation: 161

C++ Separated static field for each derived class

For quite a long time as was thinking about solution to my problem and I finally came to point when I have no other ideas but to ask here.

I have following problem.

Short version. How to inherit static field from base class, but make it unique in each derived class and keep possibility to upcast those classes to parent class?

Long version. I need to create some kind of basic interface for set of classes. Each of this classes need to have one static field and one static method. But I want to be able to pass all those classes as parameters to one universal function which uses those static members. So I was thinking about inheriting them all from one base class.

But of course I can't simply inherit static members and expect them to be unique in each child class. I was trying to use Curiously Recurring Template Pattern (CRTP), but it forces me to make this universal function template too and directly give it class name during each call. That's not good for me.

Also I have problems with making CRTP works when more than one level of inheritance is used (i.e. when I want to derive one more class from class derived from this template base class). Is there any way to achieve what I need?

I know that similar questions were already asked but in most of them authors were glad with CRTP. For me it doesn't seem like solution good enough.

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

Upvotes: 4

Views: 1533

Answers (2)

Serge
Serge

Reputation: 12384

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

Upvotes: 1

txtechhelp
txtechhelp

Reputation: 6777

Keep in mind that static variables must also be defined. So for every derived type that you need a separate static variable for, you'll need to define it as well.

Instead, you could use a std::map and a type-id hash to do something similar without the need to clutter your base class. Additionally, this allows you to have any type be used, 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;
}

This also avoids the need to declare each derived classes static members.

This may not be a good solution for your specific use case, but it is an alternative that achieves what you're asking.

Hope that can help.

Upvotes: 1

Related Questions