views:

205

answers:

5

I have a bunch of C++ classes.

I want each class to have something like:

static int unique_id;

All instances of a same class should have the same unique_id; different classes should have different unique_id's.

The simplest way to do this appears to be threading a singleton through the classes.

However, I don't know what's called when for static class members / things that happen before main.

(1) if you have a solution that does not involve using singleton, that's fine too

(2) if you have a solution that gives me a :

int unique_id(); 

that is fine too.

Thanks!

+6  A: 

Have a class that increments it's ID on each creation. Then use that class as a static field in each object that is supposed to have an ID.

class ID
{
    int id;
public:
    ID() {
        static int counter = 0;
        id = counter++;
    }

    int get_id() {  return id; }
};

class MyClass
{
    static ID id;
public:
    static int get_id() 
    {
        return id.get_id();
    }
};
Kornel Kisielewicz
-1 Each instance of the class have the same value.Different classes have different values.
anon
@anon, don't downvote if you don't understand the solution, ask for a clarification.
Kornel Kisielewicz
You're right. This is my screw up. Can you "edit" your post so I can up vote you instead? (Vote too old to be changed).
anon
@anon, no offence taken, just don't jump the gun to early :)
Kornel Kisielewicz
@Korenl thanks for coming back and pointing out I misunderstood (instead of silently ignoring me); your solution is pretty cool.
anon
@anon, no problem I can understand that the the statement without code might have been hard to parse :P
Kornel Kisielewicz
Here you've got my +1.
bodom_lx
You need to define the `ID::id` member. And class definition end with a `;` in C++. `:o>` Also, you can put all the mechanics into its own class, so that all you need to do is derive from that. See http://stackoverflow.com/questions/2172879/2173034#2173034
sbi
I think the `counter` in the `ID` constructor should be class level, not method level, mostly because I think the idea of a static in a member function, especially an inline one, is kind of confusing.
Omnifarious
...oh yeah, and the `get_id()` member(s) should probably be `static`.
sbi
@sbi, I corrected what you pointed out. Thanks -- I wrote it from memory, hence the errors.
Kornel Kisielewicz
+1  A: 

First, why? In any case, you can manually set the IDs easily:

template <int id>
struct base { enum { unique_id = id }; };

class foo: public base<5> { ... };
class bar: public base<10> { ... };

Then

foo x;
bar y;
assert(x.unique_id == 5);
assert(y.unique_id == 10);

Of course, you'll have to manually keep track of the IDs for each class; at this point, I'll ask the original question: why?

Jesse Beder
+1  A: 

C++ has this already built in.

You can use the typeid operator to return a type_info class. The type_info:name() will return the (unique) name of the class.

doron
You will have to have RTTI enabled though.
doron
How do I get an integer instead of a string?
anon
@anon, type_info unfortuantely doesn't have such a field (a shame, really). You can typecast the type_info address to a integer, but that would be a fugly solution though.
Kornel Kisielewicz
Watch out. TTBOMK, the result of `std::type_info::name()` is unspecified. While all implementations I know return something that makes sense, I don't think the standard mandates that. An implementation could return `"foo"` or an empty string and still be standard-conforming.
sbi
+3  A: 

Actually that's very similar to RTTI. To achieve (2), C++'s buildin RTTI can be exploited. Call typeid on *this, and take the address of the typeinfo as unique ID.

Conss: a) IDs aren't be fixed (recompile would change them), and b) the information is only available given an instance of the class, c) it's ugly.

Why do you want this?

Alexander Gessler
+4  A: 

Building on Kornel's solution:

class id_impl {
  private:
    id_impl() {}
    static int get_next_id()
    {
      static int counter = 0;
      return ++counter;
    }
    template< class T >
    friend class id_base;
};

template< class T >
class id_base : private id_impl
{
  public:
    static int get_id() { return id; }
  private:
    static int id;
};

template< class T >
int id_base<T>::id id = get_next_id();

Use it like this:

class my_class : public id_base<my_class> {
  // ...
};
sbi
What does the extra complication buy you?
Omnifarious
It's only a complication for the _creator_ of `id_base`. For _users_ of it, it's a simplification: they only need to derive from the class and don't have to copy that `get_id()` member into all their classes.
sbi
Ahh, OK. It's the curiously recurring template idiom in order to save a lot of tedious work.
Omnifarious
Minor nitpicking, `ID<T>::id_base id` should be `int id_base<T>::id`. :)
Georg Fritzsche
@gf: Thank you. (I started out by editing Kornel's answer and forgot to change that one...)
sbi
+1: yes, that's a nice extension, I only provided the skeleton of the solution.
Kornel Kisielewicz
Your code does not compile, http://codepad.org/QipqYlPE you need to change int id_base<T>::id id = get_next_id(); to int id_base<T>::id = get_next_id(); a working version is here http://codepad.org/zckHKJHI
Beh Tou Cheh
@ sbi ... this is amazing. My coder has become much cleaner after this. Please explain to me, why does the "template< class T >int id_base<T>::id id = get_next_id();" not result in multiple copy of id_base<T>::id being defined?
anon
@anon: It does - one for each type. I thought that's what you wanted?
sbi
@Beh Tou Cheh: Thank you for posting a corrected version of the code. I hadn't tried to compile it. Sorry for that.
sbi
@sbi: no problems.
Beh Tou Cheh