shrike shrike - 3 months ago 12
C++ Question

How to find the common parent of two classes in a class hierarchy

I have a single inheritance class hierarchy defined as follows :

struct A { using Parent = void; void fnct() { std::cout << "A\n"; } };
struct AA : A { using Parent = A; void fnct() { std::cout << "AA\n"; } };
struct AB : A { using Parent = A; void fnct() { std::cout << "AB\n"; } };
struct AAA : AA { using Parent = AA; void fnct() { std::cout << "AAA\n"; } };
struct AAB : AA { using Parent = AA; void fnct() { std::cout << "AAB\n"; } };
struct ABA : AB { using Parent = AB; void fnct() { std::cout << "ABA\n"; } };
struct ABB : AB { using Parent = AB; void fnct() { std::cout << "ABB\n"; } };


Each class in the hierarchy defines an alias
Parent
to its direct parent class, and a member function
void fnct()
.

I needed to define a template function
call_fnct_upto_parent<P,C>(C&)
which, for a given object of class
C
and a given parent class
P
of the class hierarchy, calls all of the member functions
fnct()
from the object type
C
up to the parent type
P
. I implemented this using SFINAE as follows :

template<class P, class C>
typename std::enable_if<!std::is_same<P,C>::value,void>::type call_fnct_upto_parent(C& c)
{
c.fnct();
static_assert(!std::is_same<typename C::Parent,void>::value, "parent not found");
call_fnct_upto_parent<P, typename C::Parent>(c);
}

template<class P, class C>
typename std::enable_if<std::is_same<P,C>::value,void>::type call_fnct_upto_parent(C& c)
{
c.fnct();
}


Function
call_fnct_upto_parent<P,C>(C&)
defined above works as expected as long as
P
is parent of
C
. For example, a call to
call_fnct_upto_parent<A>(aaa)
, where
aaa
is of type
AAA
, results in subsequent calls to
aaa.AAA::fnct()
,
aaa.AA::fnct()
and
aaa.A::fnct()
, resolved at compile time.

Now, I would like to define a template function
call_fnct_upto_common_parent<Ch,Co>(Co&)
which, for a given object of class
Co
and a given class
Ch
of the class hierarchy, calls all of the member functions
fnct()
from the object type
Co
up to the type
P
of the closest common parent to classes
Ch
and
Co
. As an example, a call to
call_fnct_upto_common_parent<AB>(aaa)
, would result in subsequent calls to
aaa.AAA::fnct()
,
aaa.AA::fnct()
and
aaa.A::fnct()
, because class
A
is the closest common parent to classes
AB
and
AAA
.

Can such a function be implemented and how ? A solution with calls resolved at compile time would be preferable, if feasible.

Thanks for help.

Answer

You could use std::is_base_of with a similar structure to your existing code:

template<class T, class U>
typename std::enable_if<!std::is_base_of<U,T>::value,void>::type 
call_fnct_upto_common_parent(U& u)
{
    u.fnct();
    static_assert(!std::is_same<typename U::Parent,void>::value, "parent not found");
    call_fnct_upto_common_parent<T, typename U::Parent>(u);
}

template<class T, class U>
typename std::enable_if<std::is_base_of<U,T>::value,void>::type 
call_fnct_upto_common_parent(U& u)
{
    u.fnct();
}
Comments