2013-02-28 26 views
7

Jeśli mam klasę Base, z co najmniej jedną funkcją wirtualną i klasą Derived, która dziedziczy po niej pojedynczo, to gwarantowane jest (uintptr_t)derived - (uintptr_t)static_cast<Base*>(derived) (przez Itanium ABI) równe zero, nawet jeśli pochodzi nie jest standardowym układem. Jednak w ogólnym przypadku nie musi to być prawda (np. Wielokrotne dziedziczenie).Cecha typu identyfikująca podstawową klasę bazową

Czy można napisać cechę, za pomocą której można wykryć, czy jedna klasa jest podstawową klasą podstawową innej?

Przydatne sekcje z Itanium ABI:

http://refspecs.linux-foundation.org/cxxabi-1.83.html

klasa Podstawowa baza

Dla klasy dynamicznej, unikalny klasą bazową (jeśli występują), z którymi dzieli wirtualny wskaźnik na przesunięcie 0. Jest to pierwsza (w bezpośredniej klasie bazowej) nie-wirtualna dynamiczna klasa bazowa, o ile istnieje.

klasa dynamiczna

Klasa wymaga wirtualny wskaźnik tabeli (ponieważ lub jego podstawy posiada jedną lub więcej funkcji wirtualnej użytkownika lub klasy wirtualne dolnej).

+4

wyrażenia badanie w ogóle nie pasuje do cytowany definicji. Patrzysz na adres podstawowego obiektu podrzędnego, podczas gdy ABI omawia kolejność wpisów wewnątrz tabeli v. –

+0

@BenVoigt: Ładnie zauważył. Powinniśmy naprawdę mieć link do ABI. –

+1

Jestem niezmiernie ciekawy, w jaki sposób można wykorzystać te informacje. –

Odpowiedz

8

ten będzie częścią kolejnego standardu Była to część wadliwego TR2 poprzez std::bases i std::direct_bases cech. Jeśli zdarzy ci się pracować z kompilatorem zawierającym wersję roboczą TR2, możesz mieć na to wsparcie. Na przykład w GCC 4.7.2:

#include <demangle.hpp> 
#include <iostream> 
#include <tr2/type_traits> 

struct T1 { }; 
struct T2 { }; 
struct Foo : T1, T2 { }; 


int main() 
{ 
    std::cout << demangle<std::tr2::direct_bases<Foo>::type>() << std::endl; 
} 

Drukuje:

std::tr2::__reflection_typelist<T1, T2> 

(demangler jest mój własny, może widzieliście go w innym miejscu).

Ufam można zbudować odpowiedni "jest polimorficzny i ma dokładnie zero lub jedną zasadę" cecha siebie.

+0

Awesome! Od dawna chciałem czegoś takiego, choć teraz nie pamiętam, za czym początkowo tego chciałem. – GManNickG

+0

"Podstawa podstawowa" w Itanium ABI różni się od "bezpośredniej bazy" w standardzie C++. Możliwe jest posiadanie wielu bezpośrednich klas bazowych, ale tylko jedna baza może być podstawowa. – Praxeolitic

0

Poniżej znajduje się dzika, nie do końca przetestowana próba zrobienia czegoś pożytecznego tylko z C++ 11 (w rzeczywistości nie wymaga ona żadnej funkcji C++ 11, ale łatwiej jest pisać w ten sposób).

Jednak ta cecha sprawdza tylko zamknięcie przechodni z „jest podstawowym klasa bazowa” nieruchomości: nie mogłem wymyślić nieinwazyjnego sposobu sprawdzenia, czy dana klasa jest bezpośredni klasa baza inny klasa.

#include <type_traits> 

template<typename B, typename D, D* p = nullptr, typename = void> 
struct is_primary_base_of : std::false_type { }; 

template<typename B, typename D, D* p> 
struct is_primary_base_of<B, D, p, 
    typename std::enable_if< 
     ((int)(p + 1024) - (int)static_cast<B*>(p + 1024)) == 0 
     >::type 
    > 
    : 
    std::true_type { }; 

Oto przykład:

struct A { virtual ~A() { } }; 

struct B : A { }; 

struct C { virtual ~C() { } }; 

struct D : B, C { }; 

struct E : virtual A, C { }; 

int main() 
{ 
    // Does not fire (A is PBC of B, which is PBC of D) 
    static_assert(is_primary_base_of<A, D>::value, "Error!"); 

    // Does not fire (B is PBC of C) 
    static_assert(is_primary_base_of<B, D>::value, "Error!"); 

    // Fires (C is not PBC of D) 
    static_assert(is_primary_base_of<C, D>::value, "Error!"); 

    // Fires (A is inherited virtually by E, so it is not PBC of E) 
    static_assert(is_primary_base_of<A, E>::value, "Error!"); 

    // Does not fire (C is the first non-virtual base class of E) 
    static_assert(is_primary_base_of<C, E>::value, "Error!"); 
} 
+0

To nie jest testowanie tego, o czym mówi ABI (zrozumiałe, ponieważ to pytanie też źle się złożyło). –

+0

@BenVoigt: OK, może, jeśli mógłbyś wyjaśnić, co powinienem przetestować, mogę spróbować zmienić odpowiedź. W przeciwnym razie po prostu go usuniemy. –

+0

Jest to pomocna odpowiedź, której nie należy usuwać. Ale możesz chcieć omówić układ instancji z układem v-table. Nie znam sposobu sprawdzania układu v-table bez wywoływania niezdefiniowanego zachowania (na przykład rzucanie funkcji wskaźnik-do-członka do typów integralnych). –

Powiązane problemy