Class for static maps

Discussion in 'C++' started by Grey Plastic, Feb 14, 2004.

  1. Grey Plastic

    Grey Plastic Guest

    I have a program where several classes each have a single static
    std::map to keep track of all the instances of that class. For each
    of these classes, I want a static lookupByID(int id) method which
    returns a pointer to the instance that the id references... e.g...

    Item * Item::lookupByID(Uint32 id);
    Level * Level::lookupByID(Uint32 id);
    Lifeform * Lifeform::lookupByID(Uint32 id);

    .... etc. Instead of rewriting the same code for each of these
    classes, I instead wrote an Indexable class...

    template <class Child> class Indexable {
    private:
    static std::map<Uint32,Child*> mapByID;
    static Uint32 _nextID;
    Uint32 _id;
    public:
    static Child * lookupByID(Uint32 id) { return mapByID[id]; }
    Indexable() { _id=_nextID++; mapByID[_id]=(Child*)this; }
    ~Indexable() { mapByID[_id]=NULL; }
    Uint32 id() const { return _id; }
    };

    and made each of my other classes subclass Indexable...

    class Item : public Indexable<Item> { ... };
    class Level : public Indexable<Level> { ... };
    class Lifeform : public Indexable<Lifeform> { ... };

    This achieves what I've wanted, but it still seems a bit weird to me.
    How would you guys handle this situation?
     
    Grey Plastic, Feb 14, 2004
    #1
    1. Advertising

  2. "Grey Plastic" <> wrote in message
    news:...
    > I have a program where several classes each have a single static
    > std::map to keep track of all the instances of that class. For each
    > of these classes, I want a static lookupByID(int id) method which
    > returns a pointer to the instance that the id references... e.g...
    >
    > Item * Item::lookupByID(Uint32 id);
    > Level * Level::lookupByID(Uint32 id);
    > Lifeform * Lifeform::lookupByID(Uint32 id);
    >
    > ... etc. Instead of rewriting the same code for each of these
    > classes, I instead wrote an Indexable class...
    >
    > template <class Child> class Indexable {
    > private:
    > static std::map<Uint32,Child*> mapByID;
    > static Uint32 _nextID;
    > Uint32 _id;
    > public:
    > static Child * lookupByID(Uint32 id) { return mapByID[id]; }
    > Indexable() { _id=_nextID++; mapByID[_id]=(Child*)this; }
    > ~Indexable() { mapByID[_id]=NULL; }
    > Uint32 id() const { return _id; }
    > };
    >
    > and made each of my other classes subclass Indexable...
    >
    > class Item : public Indexable<Item> { ... };
    > class Level : public Indexable<Level> { ... };
    > class Lifeform : public Indexable<Lifeform> { ... };
    >
    > This achieves what I've wanted, but it still seems a bit weird to me.
    > How would you guys handle this situation?


    It's a well known technique. Make a base class aware of a derived class by
    passing the derived class as a template parameter to the base class.
    Congratulations on discovering it yourself I'd say.

    john
     
    John Harrison, Feb 15, 2004
    #2
    1. Advertising

  3. Grey Plastic

    Sharad Kala Guest

    "John Harrison" <> wrote in message
    news:c0md56$18jf3u$-berlin.de...
    >
    > "Grey Plastic" <> wrote in message
    > news:...
    > > I have a program where several classes each have a single static
    > > std::map to keep track of all the instances of that class. For each
    > > of these classes, I want a static lookupByID(int id) method which
    > > returns a pointer to the instance that the id references... e.g...
    > >
    > > Item * Item::lookupByID(Uint32 id);
    > > Level * Level::lookupByID(Uint32 id);
    > > Lifeform * Lifeform::lookupByID(Uint32 id);
    > >
    > > ... etc. Instead of rewriting the same code for each of these
    > > classes, I instead wrote an Indexable class...
    > >
    > > template <class Child> class Indexable {
    > > private:
    > > static std::map<Uint32,Child*> mapByID;
    > > static Uint32 _nextID;
    > > Uint32 _id;
    > > public:
    > > static Child * lookupByID(Uint32 id) { return mapByID[id]; }
    > > Indexable() { _id=_nextID++; mapByID[_id]=(Child*)this; }
    > > ~Indexable() { mapByID[_id]=NULL; }
    > > Uint32 id() const { return _id; }
    > > };
    > >
    > > and made each of my other classes subclass Indexable...
    > >
    > > class Item : public Indexable<Item> { ... };
    > > class Level : public Indexable<Level> { ... };
    > > class Lifeform : public Indexable<Lifeform> { ... };
    > >
    > > This achieves what I've wanted, but it still seems a bit weird to me.
    > > How would you guys handle this situation?

    >
    > It's a well known technique. Make a base class aware of a derived class by
    > passing the derived class as a template parameter to the base class.
    > Congratulations on discovering it yourself I'd say.


    And it's called the "Curiously recurring template pattern (CRTP)".
    Also as you have correctly noted that even though the base class depends
    on the derived class, it cannot do so in a way that requires the complete type
    of derived to be known. That means you can refer to Child*/Child& but not Child
    in the base class.

    -Sharad
     
    Sharad Kala, Feb 15, 2004
    #3
  4. "Sharad Kala" <> wrote in message
    news:c0n1uf$18ln0p$-berlin.de...
    >
    > "John Harrison" <> wrote in message
    > news:c0md56$18jf3u$-berlin.de...
    > >
    > > "Grey Plastic" <> wrote in message
    > > news:...
    > > > I have a program where several classes each have a single static
    > > > std::map to keep track of all the instances of that class. For each
    > > > of these classes, I want a static lookupByID(int id) method which
    > > > returns a pointer to the instance that the id references... e.g...
    > > >
    > > > Item * Item::lookupByID(Uint32 id);
    > > > Level * Level::lookupByID(Uint32 id);
    > > > Lifeform * Lifeform::lookupByID(Uint32 id);
    > > >
    > > > ... etc. Instead of rewriting the same code for each of these
    > > > classes, I instead wrote an Indexable class...
    > > >
    > > > template <class Child> class Indexable {
    > > > private:
    > > > static std::map<Uint32,Child*> mapByID;
    > > > static Uint32 _nextID;
    > > > Uint32 _id;
    > > > public:
    > > > static Child * lookupByID(Uint32 id) { return mapByID[id]; }
    > > > Indexable() { _id=_nextID++; mapByID[_id]=(Child*)this; }
    > > > ~Indexable() { mapByID[_id]=NULL; }
    > > > Uint32 id() const { return _id; }
    > > > };
    > > >
    > > > and made each of my other classes subclass Indexable...
    > > >
    > > > class Item : public Indexable<Item> { ... };
    > > > class Level : public Indexable<Level> { ... };
    > > > class Lifeform : public Indexable<Lifeform> { ... };
    > > >
    > > > This achieves what I've wanted, but it still seems a bit weird to me.
    > > > How would you guys handle this situation?

    > >
    > > It's a well known technique. Make a base class aware of a derived class

    by
    > > passing the derived class as a template parameter to the base class.
    > > Congratulations on discovering it yourself I'd say.

    >
    > And it's called the "Curiously recurring template pattern (CRTP)".
    > Also as you have correctly noted that even though the base class depends
    > on the derived class, it cannot do so in a way that requires the complete

    type
    > of derived to be known. That means you can refer to Child*/Child& but not

    Child
    > in the base class.
    >
    > -Sharad
    >


    I don't think that's right. How about this?

    template <class Rep>
    class RCObject
    {
    friend class RCPtr<Rep>;
    public:
    RCObject() : _ref(0) {}
    RCObject(const RCObject<Rep>&) : _ref(0) {}
    RCObject<Rep>& operator=(const RCObject<Rep>&) {}
    ~RCObject() { assert(_ref == 0); }
    Rep* clone() const { return new Rep(*static_cast<const Rep*>(this)); }
    private:
    size_t _ref;
    };

    RCObject is a base class for intrusively reference counted objects. It
    defines a clone method that calls the derived class copy ctor and therefore
    needs to have the complete type.

    I think the point is that Rep needs to be known when RCObject is
    instantiated not when it is compiled.

    john
     
    John Harrison, Feb 15, 2004
    #4
  5. Grey Plastic

    Sharad Kala Guest


    >
    > I think the point is that Rep needs to be known when RCObject is
    > instantiated not when it is compiled.
    >

    True, I should I have been clearer.
    The error will come during the instantiation of the base class.

    In this code -

    template<typename T>
    struct B {
    T p;
    };

    struct D: B<D> { // CRTP
    };
    int main(){
    }

    When B tries to get instatntiated with T=D, compiler would throw hands saying
    B<T>::p has incomplete type.

    Best wishes,
    Sharad
     
    Sharad Kala, Feb 15, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. SaravanaKumar
    Replies:
    6
    Views:
    9,452
    Tony Morris
    Oct 19, 2004
  2. Simon Elliott
    Replies:
    0
    Views:
    385
    Simon Elliott
    Jan 11, 2005
  3. Simon Elliott
    Replies:
    4
    Views:
    1,173
    Simon Elliott
    Mar 10, 2005
  4. Marcus
    Replies:
    2
    Views:
    598
    Marcus
    Dec 9, 2005
  5. Replies:
    4
    Views:
    115
Loading...

Share This Page