2017-05-06 3 views
7

Angenommen man eine Klassenhierarchie hat, ohne Mehrfachvererbung:gemeinsame Basisklasse

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

Ist es möglich, eine metafunction zu schreiben, die die Art der gemeinsamen Basis von zwei Typen zurück? (Es könnte void zurück, wenn nicht gemeinsame Basisklasse existiert.) Zum Beispiel

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 

Offensichtlich wäre dies nicht mit mehreren inhertance arbeiten, aber ich bin es in dem einzelnen Vererbungs Fall konzentriert.

Erstens scheint es nicht möglich zu sein ohne eine gewisse Introspektion der Basisklasse. Also, ich habe dies einfaches Problem, tun Sie es so, dass jeder clase seine Basis kennt (durch einen internen base-Typen), zum Beispiel:

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

Auch auf diese Weise kann ich das metaprogramming scheinen, Recht.

Auch habe ich irgendwo gelesen (ich kann es jetzt nicht finden), dass GCC einige Erweiterungen hat, um gemeinsame Basisklasse zu erkennen. Ist das der Fall?

+0

Würde 'common_base :: type' 'RR' oder' R' sein? –

+0

@JamesRoot, 'RR'. – alfC

Antwort

3

Es gab irgendwann bases und direct_bases in std :: tr2 but that wasn't included. Einige Versionen von gcc haben es. Mit diesen können Sie vielleicht bekommen, was Sie wollen.

+0

Danke für den Zeiger. Ich bekomme einen Fehler nur mit '#include type; ') – alfC

+0

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

+0

@alfC Du wirst wahrscheinlich mehr Glück haben wenn Sie auf gcc 4.8.0 oder etwas ähnliches herunterstufen. – Pavel

1

Wenn Sie jede Klasse alias die Basis als base haben (wie unten), kann es getan werden.

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

Ich habe eine struct:

template <class T1, class T2> 
struct CommonBase; 

CommonBase Werke von jeder Basis von T2-T1 zu vergleichen. Wenn es die oberste Ebene erreicht, beginnt es wieder unten, vergleicht aber mit der Basis von T1.

Zum Beispiel: CommonBase<RL, RR> würde folgende Prüfungen durchlaufen:

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

So CommonBase<RL, RR>::type == R. Wenn es keine gemeinsame Basis gibt, type == void.

habe ich den Code am Ende, weil Metaprogrammierung so schön ist:

#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 Sie es auf einigen Testfälle sehen.

Verwandte Themen