0

I'd like a static counter that is incremented each time I create another type, class. Here is what I've tried:

template <typename Type>
class Sequential_ID_Dispenser
{public:
    static inline int nextDispensed = 0;
    static int getID() { return nextDispensed++; }
};

struct DummyTypeForComponentIDs {}; // So that the same type is passed to getID()

template <typename T>
struct Component { 
    static inline int componentTypeID = Sequential_ID_Dispenser<DummyTypeForComponentIDs>::getID();
    
    
};

// The reason I've made it inherit like this is so that any time I add a new Component type/struct it'll automatically get an ID for that type
struct Hat : Component<Hat> {};
struct Tie : Component<Tie> {};

int main()
{
    

    int id = Hat::componentTypeID; // = 0
    id = Tie::componentTypeID; // = 1
}

This works. But I want to have the option of easily inheriting from any other component, and it doesn't work like this, for example:

template <typename T>
    struct Component { 
        static inline int componentTypeID = Sequential_ID_Dispenser<DummyTypeForComponentIDs>::getID();
   };

    struct Hat : Component<Hat> {};
    struct Tie : Component<Tie> {};
    struct BlueHat : Hat {};

int main()
{
    int id = Hat::componentTypeID; // = 0
    id = Tie::componentTypeID; // = 1
    
    id = BlueHat::componentTypeID; // = 0, gets the same number as struct Hat : Component<Hat>{}
}

Is there a good solution for this? I'd like to ideally just define any new struct without passing arguments to the base constructor. I realise that I've CRTP for this, it's just what I did to make it work, but there must be simpler way, right?

Edit: Actually I'm surprised the solution isn't easier, all I'd like is for each class I create in the global namespace to get a new ID, I guess either compile time or runtime.

Zebrafish
  • 11,682
  • 3
  • 43
  • 119

2 Answers2

5

You don't need inheritance for (runtime) counters on types.

You might even use a template variable (C++14):

std::size_t getId()
{
    static std::size_t counter = 0;
    return counter++;
}

template <typename T>
std::size_t Id = getId();

Demo.

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

I can't see an easy way to extend your current solution to do this, unless you want to start throwing virtual on every inheritance declarator, and remember to do this each time.

It seems like a bit of an anti-pattern to "count types", anyway. We already have unique type identifiers, by way of typeid.

If you really need an int, you can have some manager class that takes a std::type_info and gives you an int unique to that type, possibly using a map to power it. But if you can just store the std::type_info in the first place instead, so much the better. The downside is that this information won't be available statically (i.e. "at compile-time").

Asteroids With Wings
  • 17,071
  • 2
  • 21
  • 35
  • Not as good as Jarod's solution, but is any of this actually wrong? Some valid alternative approaches (virtual inheritance fixes the original problem, and `type_info` _is_ the proper way to identify types). A downvote seems a bit much. – Asteroids With Wings Dec 23 '20 at 00:12