Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Class for static maps

Reply
Thread Tools

Class for static maps

 
 
Grey Plastic
Guest
Posts: n/a
 
      02-14-2004
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?
 
Reply With Quote
 
 
 
 
John Harrison
Guest
Posts: n/a
 
      02-15-2004

"Grey Plastic" <(E-Mail Removed)> wrote in message
news:(E-Mail Removed) om...
> 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


 
Reply With Quote
 
 
 
 
Sharad Kala
Guest
Posts: n/a
 
      02-15-2004

"John Harrison" <(E-Mail Removed)> wrote in message
news:c0md56$18jf3u$(E-Mail Removed)-berlin.de...
>
> "Grey Plastic" <(E-Mail Removed)> wrote in message
> news:(E-Mail Removed) om...
> > 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



 
Reply With Quote
 
John Harrison
Guest
Posts: n/a
 
      02-15-2004

"Sharad Kala" <(E-Mail Removed)> wrote in message
news:c0n1uf$18ln0p$(E-Mail Removed)-berlin.de...
>
> "John Harrison" <(E-Mail Removed)> wrote in message
> news:c0md56$18jf3u$(E-Mail Removed)-berlin.de...
> >
> > "Grey Plastic" <(E-Mail Removed)> wrote in message
> > news:(E-Mail Removed) om...
> > > 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


 
Reply With Quote
 
Sharad Kala
Guest
Posts: n/a
 
      02-15-2004

>
> 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>: has incomplete type.

Best wishes,
Sharad


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
MSN maps vs. Google maps Ralph Fox NZ Computing 0 07-30-2007 10:30 AM
STL: Map of maps possible, but no multi-map of maps? Workarounds? Marcus C++ 2 12-09-2005 06:34 AM
PIX public/24 ip static mapping means 256 times interfaces static maps? Nieuws Xs4all Cisco 2 05-26-2005 06:25 PM
PIX public/24 ip static mapping means 256 times interfaces static maps? Nieuws Xs4all Cisco 0 05-26-2005 11:07 AM
std::maps within std::maps -- optimisation Simon Elliott C++ 4 03-10-2005 10:11 AM



Advertisments