Detect common base class

Suppose one has a class hierarchy, without multiple inheritance:

struct TOP{};
struct L : TOP{}; 
struct R : TOP{};
struct LL : L{};
struct LR : L{};
struct RL : R{};
struct RR : R{};

Is it possible to write a metafunction that will return the type of the common base of two types? (it could return void if not common base class exists.) For example

common_base<RR, R>::type == R
common_base<RL, RR>::type == R
common_base<LL, RR>::type == TOP
common_base<LL, std::string>::type == void

Obviously this wouldn't work with multiple inhertance, but I am focused in the the single inheritance case.

First, it doesn't seem to be possible without some introspection of the base class. So, I have this easier problem, do it in such a way that each clase knows its base (by an internal base type), for example:

struct LR : L{using base = L;};

Even in this way, I cannot seem to get the metaprogramming right.

Also I read somewhere (I can't find it now) that GCC has some extensions to detect common base class. Is that the case?


There was at some point bases and direct_bases in std::tr2 but that wasn't included. Some versions of gcc have it. Using these perhaps you can get what you want.


If you have each class alias the base as base (like below), it can be done.

struct Child : Parent { using base = Parent; }; //typedef works too

I created a struct :

template <class T1, class T2>
struct CommonBase;

CommonBase works by comparing every base of T2 to T1 . When it reaches the top level base, it starts at the bottom again, but compares against the base of T1 .

For example: CommonBase<RL, RR> would go through the following checks:

RL !=  RR
RL !=  R
RL !=  Top
R  !=  RR
R  ==  R

So CommonBase<RL, RR>::type == R . If there is no common base, type == void .

I put the code at the end because template metaprogramming is so pretty:

#include <type_traits>

template <class T>
struct GetBase //type = T::base, or else void
{
    template <class TT> static typename TT::base& f(int);
    template <class TT> static void f(...);
    typedef std::remove_reference_t<decltype(f<T>(0))> type;
};

template <class T1, class T2>
struct Compare2 //Compares T1 to every base of T2
{
    typedef typename GetBase<T2>::type _type;
    template <class T, bool = !std::is_same<T, void>::value>
    struct helper
    {
        typedef typename Compare2<T1, T>::type type;
    };
    template <class T>
    struct helper<T, false>
    {
        typedef void type;
    };
    typedef typename helper<_type>::type type;
};

template <class T>
struct Compare2<T, T>
{
    typedef T type;
};

template <class T1, class T2>
struct Compare1 //Uses Compare2 against every base of T1
{
    typedef typename GetBase<T1>::type _type;
    template <class T, bool = !std::is_same<T, void>::value>
    struct helper
    {
        typedef typename Compare1<T, T2>::type type;
    };
    template <class T>
    struct helper<T, false>
    {
        typedef void type;
    };
    typedef std::conditional_t<std::is_same<typename Compare2<T1, T2>::type, void>::value, typename helper<_type>::type, typename Compare2<T1, T2>::type> type;
};

template <class T>
struct Compare1<T, T> //Probably redundant
{
    typedef T type;
};

template <class T1, class T2>
struct CommonBase //You can throw a std::enable_if on this to limit it to class types
{
    typedef typename Compare1<T1, T2>::type type;
};

Here you can see it on some test cases.

链接地址: http://www.djcxy.com/p/96220.html

上一篇: 纯JavaScript来禁用div中的所有表单元素

下一篇: 检测通用基类