2017-05-06 9 views
7

と仮定1は、多重継承せずに、クラス階層を持っていますは、共通の基本クラスを検出

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

は、それには2つのタイプの一般的な塩基の種類を返します。メタ関数を記述することは可能ですか? (ない共通の基底クラスが存在する場合、それはvoidを返すことができます。) 例えば

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 

明らかにこれは、複数のinhertanceでは動作しないだろうが、私は、単一継承の場合に焦点を当てています。

まず、基本クラスのイントロスペクションがなければ、それは可能ではないようです。だから、私はこれを簡単な問題を持って、各CLASEは(内部baseタイプによって)そのベースを知っているような方法でそれを行う、例えば:

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

でも、このように、私はメタプログラミングを得るように見えることはできません右。

また、GCCに共通の基底クラスを検出するための拡張機能がいくつかあります(私はそれを見つけることができません)。それは事実ですか?

+0

'common_base :: type'は' RR'か 'R'ですか? –

+0

@JamesRoot、 'RR'。 – alfC

答えて

3

std :: tr2 but that wasn't includedには、basesdirect_basesがありました。 gccのいくつかのバージョンがあります。これらを使って、あなたが望むものを得ることができます。

+0

ポインタありがとうございます。 6.3.1/tr2/type_traits:90:45:致命的なエラー: '_Tp'は値を参照していません typedef __reflection_typelist <__ bases (_Tp)...>タイプ; ') – alfC

+0

GCCリンク:https://gcc.gnu.org/onlinedocs/gcc-4.7.2/libstdc++/api/a00909.html – alfC

+0

@alfC gcc 4.8.0などにダウングレードした場合 – Pavel

1

各クラスエイリアスにbase(下のように)というベースがある場合、これを実行できます。

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

私はstructを作成しました:

template <class T1, class T2> 
struct CommonBase; 

CommonBaseT1T2のすべてのベースを比較することによって動作します。トップレベルのベースに達すると、再び底部から開始されますが、T1のベースと比較されます。例えば

CommonBase<RL, RR>は、以下のチェックを通過します:

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

のでCommonBase<RL, RR>::type == R。共通のベースがない場合は、type == void

テンプレートメタプログラミングがとてもきれいですので、私は最後にコードを置く:

#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をあなたには、いくつかのテストケースにそれを見ることができます。

関連する問題