CRTP idiom and a C-ish types system can help in this case:
#include<cstddef>
#include<cassert>
struct B {
static std::size_t cnt() noexcept {
static std::size_t val = 0;
return val++;
}
};
template<typename T>
struct I: private B {
static std::size_t type() noexcept {
static std::size_t t = B::cnt();
return t;
}
};
struct T: I<T> { };
struct S: I<S> { };
int main () {
assert(T::type() != S::type());
T t1, t2;
S s;
assert(t1.type() == t2.type());
assert(t1.type() != s.type());
}
You can use a macro as it follows too:
#define TypedStruct(C) struct C: I<C>
// ...
TypedStruct(T) { };
TypedStruct(S) { };
As mentioned in the comments, if you don't want it to interfere with your classes, you can use a similar approach as it follows:
#include<cstddef>
#include<cassert>
struct B {
static std::size_t cnt() noexcept {
static std::size_t val = 0;
return val++;
}
};
template<typename T>
struct Type: private B {
static const std::size_t type;
};
template<typename T>
const std::size_t Type<T>::type = B::cnt();
struct T { };
struct S { };
int main () {
assert(Type<T>::type != Type<S>::type);
}
As you can see, S
and T
are not affected by the Type
class.
The latter can be used at any time to give them an unique identifier.