Jagannath
Jagannath

Reputation: 4025

Detecting Inheritance during compile time

I am unable to figure out why this code is returning false. I had the first version of partial specialization. It did not work, I tried with the second version. It did not work either.

UPDATE: I wanted to check if "Derived" is publicly derived from "Base".

UPDATE:

    template<typename TDerived, typename TBase>
    struct Derived_From
    {

    public:
        static void constraints(TBase*, TDerived* ptr) { TBase* b = ptr; ignore(b); }
        Derived_From() { void (*p)(TBase*, TDerived*) = constraints; ignore(p);}
    };

I found the above code snippet in Strostrup's homepage. But, it does not let the code compile if the derived class is not publicly derived from Base.

template<class TBase, class TDerived>
struct IsDerived
{
    public:
    enum { isDerived = false };
};


template<class TBase>
struct IsDerived<TBase, TBase>
{
    public:
    enum {  isDerived = true };
};


template<class TBase>
struct IsDerived<TBase&, TBase&>
{
    public:
    enum {  isDerived = true };
};

int main()
{
    cout << ((IsDerived<Base&, Derived&>::isDerived) ? "true" : "false")
         << endl;
    cout << ((IsDerived<const Derived*, const Base*>::isDerived) ?
            "true" : "false") << endl;

} 

Upvotes: 7

Views: 445

Answers (4)

Ben Voigt
Ben Voigt

Reputation: 283803

I always just use pointer initialization for this. Pointers implicitly convert only to a supertype (could be identity conversion or public base class), so it won't compile unless that relationship exists (and in the right direction).

e.g.

Parent* p = (Possibly_Derived*)0;

Oh wait, you're not wanting compilation to fail, but to set a variable? Here:

template<typename TParent>
bool is_derived_from( TParent* ) { return true; }

template<typename TParent>
bool is_derived_from( void* ) { return false; }

cout << is_derived_from<Parent>( (Possibly_Derived*)0 );

Here's a demo: http://ideone.com/0ShRF

Upvotes: 7

P M
P M

Reputation: 857

If I am right, you are calling the Template with 2 different Parameter types..

(IsDerived<Base&, Derived&>::isDerived)

Thus it will invoke

struct IsDerived
{
    public:
    enum { isDerived = false };
};

and this is why IsDerived<Base&, Derived&>::isDerived as well as IsDerived<const Derived*, const Base*>::isDerived is false.

calls like (IsDerived<Base&, Base&>::isDerived) will return True.

I wanted to check if "Derived" is publicly derived from "Base".

I am not aware of Template based solution, and will keep a eye on this thread. but i usually exploit dynamic_cast to do this job, if ever needed.

If dynamic_cast cannot cast a pointer because it is not a complete object of the required class, it returns a null pointer to indicate the failure.

If dynamic_cast is used to convert to a reference type and the conversion is not possible, an exception of type bad_cast is thrown instead.

Upvotes: 0

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84239

Check out boost type traits, specifically the is_base_of template.

Upvotes: 7

JP19
JP19

Reputation:

Firstly, I assume you want a generic method to work for any classes, without modifying or adding any function to the class. I think this template method cannot work. A derived class is not equal to the base class, and unless the two classes are EQUAL, the specialized struct will not be instantiated. Similarly, pointer to derived class is not equal to pointer to base class.

I assume you already know that people regularly use virtual functions to check if the "object" is of base class or derived class.

(Note that I am not saying what you want cannot be done - just that the results you are seeing are expected and the template approach will not work).

Upvotes: 1

Related Questions