If I understood you correctly, you want a type inheritance_checker
such that each instation of it is associated to a type but inheritance_checker
itself is not. Something similar to type_ifo
but that can check inheritance relationships at runtime. For example, you want the following to work:
class A {};
class B : public A {};
// Note that a and b have the same type but they are "related" to distinct types.
inheritance_checker a = inheritance_checker::create<A>();
inheritance_checker b = inheritance_checker::create<B>();
assert( a.is_base_of (b) );
assert( a.derives_from(a) ); // derives from or is equal to
assert( ! b.is_base_of (a) );
assert( b.derives_from(b) ); // derives from or is equal to
If this is the case, I can suggest you something that, unfortunately, can be quite slow! It depends on exceptions.
The basic idea is that if you throw a B*
then a catch (A*)
is a match. Hence, we give to inheritance_checker
the ability to throw and catch pointers to the type given at construction time. But inheritance_checker
is not a template and therefore this capacity must be provided in a type-erased way. This can be done by storing pointers to functions that have a fixed signature that doesn't depend on the type passed at construction but are capable of throwing/catching pointers to the given type. A possible implementation of inheritance_checker
is given below.
#include <cassert>
class inheritance_checker {
typedef void (*thrower_t)();
typedef bool (*catcher_t)(thrower_t);
public:
template <typename T>
static inheritance_checker create() {
return inheritance_checker(concrete_thrower<T>, concrete_catcher<T>);
}
bool is_derived_from(const inheritance_checker& other) const {
return other.catcher_(thrower_);
}
bool is_base_of(const inheritance_checker& other) const {
return catcher_(other.thrower_);
}
private:
template <typename T>
static void concrete_thrower() {
throw static_cast<T*>(nullptr);
}
template <typename T>
static bool concrete_catcher(thrower_t thrower) {
try { thrower(); }
catch (T*) { return true; }
catch (...) { }
return false;
}
inheritance_checker(thrower_t thrower, catcher_t catcher) :
thrower_(thrower), catcher_(catcher) {
}
thrower_t thrower_;
catcher_t catcher_;
};
class A {};
class B : public A {};
class C : public B {};
class D {};
int main() {
auto a = inheritance_checker::create<A>();
auto b = inheritance_checker::create<B>();
auto c = inheritance_checker::create<C>();
auto d = inheritance_checker::create<D>();
assert( a.is_base_of(a));
assert( a.is_base_of(b));
assert( a.is_base_of(c));
assert(!a.is_base_of(d));
assert( a.is_derived_from(a));
assert(!a.is_derived_from(b));
assert(!a.is_derived_from(c));
assert(!a.is_derived_from(d));
assert(!b.is_base_of(a));
assert( b.is_base_of(b));
assert( b.is_base_of(c));
assert(!b.is_base_of(d));
assert( b.is_derived_from(a));
assert( b.is_derived_from(b));
assert(!b.is_derived_from(c));
assert(!b.is_derived_from(d));
assert(!c.is_base_of(a));
assert(!c.is_base_of(b));
assert( c.is_base_of(c));
assert(!c.is_base_of(d));
assert( c.is_derived_from(a));
assert( c.is_derived_from(b));
assert( c.is_derived_from(c));
assert(!c.is_derived_from(d));
assert(!d.is_base_of(a));
assert(!d.is_base_of(b));
assert(!d.is_base_of(c));
assert( d.is_base_of(d));
assert(!d.is_derived_from(a));
assert(!d.is_derived_from(b));
assert(!d.is_derived_from(c));
assert( d.is_derived_from(d));
}
If you wish, you might add a type_info*
member to inheritance_checker
to get the extra functionality that type_info
provides.
Notice the symmetry between is_base_of
and derives_from
. Actually, you can remove one of them.
I suggest you to read this article.
type_info
representing the runtime-type of your objects. How should this ever be possible. You already know their static type, it'sobject*
(and that's also whatdecltype(*objects.begin())
will return), but that doesn't help you in any way. So templates are entirely out of the question, since the solve a completely different problem and cannot be used for RTTI. – Caaba