1

So, this question has been asked before, but I wanted a question with some of those key words in the title.

The issue is simple: How can I have a templated class, such that for each instance of the template - but not each instance of the class - there is a unique, numerical identifier?

That is, a way to differentiate:

foo<int> f1;
foo<char> f2;
classID(f1) != classID(f2);

but,

foo<int> f3;
foo<int> f4;
classID(f3) == classID(f4);

Related to:

in C++, how to use a singleton to ensure that each class has a unique integral ID?

Assigning Unique Numerical Identifiers to Instances of a Templated Class

Community
  • 1
  • 1
Narfanator
  • 5,595
  • 3
  • 39
  • 71

2 Answers2

2
template<class T>
class Base
{
public:
    static void classID(){}
private:
    T* t;
};

int main()
{
    Base<int> foo;
    Base<int> foo2;
    Base<char> foo3;

    /*
    unsigned int i  = reinterpret_cast<unsigned int>(Base<int>::classID);
    unsigned int ii = reinterpret_cast<unsigned int>(Base<char>::classID);
    unsigned int iii = reinterpret_cast<unsigned int>(Base<int>::classID);
    /*/
    unsigned int i  = reinterpret_cast<unsigned int>(foo.classID);
    unsigned int ii  = reinterpret_cast<unsigned int>(foo2.classID);
    unsigned int iii  = reinterpret_cast<unsigned int>(foo3.classID);
    //*/

    return ((i != ii) + (i <= ii) + (i >= ii)) == 2;
}

That's how! It's lightweight, super easy, and doesn't use RTTI, although it uses the ridiculously unsafe reinterpret_cast.

Although, maybe I'm missing something?

Narfanator
  • 5,595
  • 3
  • 39
  • 71
  • I've selected my own answer because it is a) simpler and b) static compile time constant, afaik. – Narfanator Feb 11 '10 at 05:29
  • I tested this with VS 2015 and it works when compiling for Debug but not when compiling for Release. When compiling for Release, the optimizer combines all classID() functions into a single one. So foo.classID == foo2.classID == foo3.classID. – adigostin Mar 17 '16 at 08:43
0

I think you can just use a static function for this, and inherit its class:

struct IdCounter { static int counter; };
int IdCounter::counter;

template<typename Derived>
struct Id : IdCounter {
  static int classId() {
    static int id = counter++;
    return id;
  }
};

struct One : Id<One> { };
struct Two : Id<Two> { };

int main() { assert(One::classId() != Two::classId()); }

Of course, that won't be a static compile time constant - i don't think that is possible automatically (you would have to add those types manually to some type list like mpl::vector). Please notice that for just comparing types for equality, you don't need all this. You just need to use is_same (found in boost and other libraries and trivial to write) which yields a compile time constant

template<typename A, typename B>
struct is_same { static bool const value = false; };
template<typename A> 
struct is_same<A, A> { static bool const value = true; };

int main() { char not_true[!is_same<One, Two>::value ? 1 : -1]; }
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • The problem with ``is_same``, AFAIK, is that it doesn't support > or <, which means it's not sortable and thus can't use any effective storage object like a tree or map. – Narfanator Feb 01 '10 at 22:33
  • This meets all requirements, however, you point out that it's not a static compile time constant? Do you know if my own answer is? (I think it would be, but I'm not sure how to test that.) – Narfanator Feb 01 '10 at 22:35