2011-11-03 7 views
9

Mam problem, w którym muszę odkryć wspólnego przodka dwóch typów (z jedną lub zerowymi klasami podstawowymi), jeśli istnieje. Czy możliwe jest zbudowanie cechy typowej w celu rozwiązania tego problemu? W kodzie:Jak wydedukować, w czasie kompilacji, główny katalog drzewa dziedziczenia wspólnego dla dwóch typów, jeśli taki istnieje?

template<typename T1, typename T2> 
    struct closest_common_ancestor 
{ 
    typedef XXX type; // what goes here? 
}; 

Przy następujących typów:

struct root {}; 
struct child1 : root {}; 
struct child2 : root {}; 
struct child3 : child2 {}; 
struct unrelated {}; 

closest_common_ancestor doprowadziłoby do następujących typów:

closest_common_ancestor<root, child1>::type == root 
closest_common_ancestor<child1, child2>::type == root 
closest_common_ancestor<child3, child1>::type == root 
closest_common_ancestor<child3, child2>::type == child2 
closest_common_ancestor<unrelated, child1>::type == error 

Wierzę, że mogę rozwiązać ten problem, czy mogę sprawdzić, czy type ma zero lub jedną klasę podstawową, a jeśli tak, to nazwę tego typu. czy to możliwe?

+2

Nie można kontrolować klas podstawowych. Nie, chyba że ręcznie dodasz metadane do każdej z twoich klas. –

+0

Zauważ, że dla bezpośredniego związku jest to już możliwe ('is_base_of' może być zaimplementowane pod względem podstawowych bloków C++ 03) –

+0

Jeśli są 2 korzenie' root1' i 'root2' i' child1', dziedziczenie 'child2' oba z nich ('struct child1: root1, root2 {};'), będzie niejednoznaczne dla 'closest_common_ancestor', co zwrócić. – kennytm

Odpowiedz

7

Jak wspomniał K-ballo, niestety nie można uzyskać listy baz, które posiada klasa (szkoda ...).

Jeśli ręcznie dodasz adnotacje do swoich klas (powiedz: zdefiniuj prosty std::tuple<> zawierający listę zasad), możesz użyć tych informacji. Prostsze, oczywiście, byłoby wykorzystanie cechę:

template <typename> struct list_bases { typedef std::tuple<> type; }; 

Następnie można specjalizować tę cechę dla swoich typów:

template <> struct list_bases<child1> { typedef std::tuple<root> type; }; 

I wychodząc stamtąd, można rozpocząć eksperyment ze znalezieniem przodka ... jednak może nie być natychmiastowe. Poza szczegółami implementacji (pobieranie rekurencyjnie baz, wdrażanie selekcji "odległości"), spodziewam się problemu z "dziwnymi" przypadkami.

Wybór odległości może w zwykły (liniowy) hierarchii spadku być rozwiązane za pomocą kombinacji is_base_of i is_same jednak rozważyć następujące hierarchii:

struct root1 {}; struct root2 {}; 

struct child1: root1 {}; struct child2: root2 {}; 

struct child12: root1, child2 {}; struct child21: root2, child1 {}; 

Teraz child12 i child21 mają dwa wspólne przodków: root1 i root2 ... która jest najbliżej?

Są one równoważne. Uważają, że dodam:

struct root3 {}; struct child31: root3, child1 {}; 

Następnie root1 jest wspólnym przodkiem child12, child21 i child31.

Jednak gdybym omijała sprawie definicji closest_common_ancestor i dowolnie definiowane że closest_common_ancesotr<child12, child21> jest root2, to nie mogłem znaleźć żadnego wspólnego przodka z child31.

Moją propozycją jest zatem lista wszystkich najbliższych przodków i użycie tuple do wykonania operacji ustawiania.

+0

Dzięki. W mojej aplikacji rozwiążę niejednoznaczność, o której wspomniałeś, podkreślając, że wszystkie rozważane typy mają tylko zero lub jeden typ podstawowy. –