如何在 class 层次结构中找到两个 class 的公共 parent

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

我有一个继承 class 层次结构,定义如下:

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"; } };

层次结构中的每个class为其直接parentclass定义了一个别名Parent,以及一个成员函数void fnct().

我需要定义一个模板函数 call_fnct_upto_parent<P,C>(C&),对于 class C 的给定 object 和给定的 parent class class 层次结构的 P,调用所有成员函数 fnct() 从 object 类型 C 到 parent 类型 P。我使用 SFINAE 实现了这个,如下所示:

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();
}

只要 PC 的 parent,上面定义的函数 call_fnct_upto_parent<P,C>(C&) 就可以正常工作。例如,调用 call_fnct_upto_parent<A>(aaa),其中 aaa 的类型为 AAA,会导致后续调用 aaa.AAA::fnct()aaa.AA::fnct()aaa.A::fnct(),在编译时解决。

现在,我想定义一个模板函数 call_fnct_upto_common_parent<Ch,Co>(Co&),对于 class Co 的给定 object 和给定的 class Ch 的 class 层次结构,调用所有成员函数 fnct() 从 object 类型 Co 到最接近的公共类型 P parent 到 class 是 ChCo。例如,对 call_fnct_upto_common_parent<AB>(aaa) 的调用将导致对 aaa.AAA::fnct()aaa.AA::fnct()aaa.A::fnct() 的后续调用,因为 class A 是最接近 parent 到 classes ABAAA.

能否实现这样的功能,如何实现?如果可行,在编译时解决调用的解决方案将是更可取的。

感谢您的帮助。

您可以使用具有与现有代码类似结构的 std::is_base_of

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();
}