2014-03-24 10 views
7
template <typename T> 
class Base 
{ 
private: 
    typename T::B c; 
}; 

class A : public Base<A> 
{ 
public: 
    class B; 
}; 

Ist so etwas überhaupt möglich? VC++ 2013 sagt B kein Mitglied von A. istKlasse A aus einer Vorlagenklasse Basis <A> ableiten, so dass Basis <A> A :: B verwenden kann?

+4

Sie können nicht, und GCC-Fehler ist aussagekräftiger als warum http://ideone.com/90siYB – StoryTeller

+1

Welche Klassen können Sie ändern, um eine Problemumgehung einzuführen? – pmr

+0

In Ihrem tatsächlichen Code ist B ein Typ oder eine Mitgliedsvariable? –

Antwort

1

ich so (live example) gehen würde:

template<typename T> struct Impl; 
template<typename T> struct Nested; 

template <typename T> 
class Base 
{ 
private: 
    typename Nested<T>::type c; 
}; 

struct A; 

template<> struct Impl<A> { class B { }; }; 
template<> struct Nested<A> { using type = typename Impl<A>::B; }; 

struct A : Base<A>, Impl<A> 
{ 
    //... 
}; 

Hier Klasse Impl enthält den Teil A, die nicht auf dem Base abhängt, das heißt, die verschachtelte Klasse B. Daher leitet A jetzt sowohl Base<A> als auch Impl<A> ab.

Die Klasse Nested enthält nur einen Alias, der den Typ der obigen geschachtelten Klasse angibt. Jetzt Base liest diesen Typ von Nested und definiert sein Datenelement dieses Typs.

Wir müssen A erklären, bevor wir Impl und Nested dafür spezialisieren. Und wir benötigen diese Spezialisierungen, bevor wir A definieren, da zu diesem Zeitpunkt Base<A> instanziiert wird, und dies erfordert, dass Nested<A> abgeschlossen ist, was wiederum erfordert, dass Impl<A> abgeschlossen ist.

Der wesentliche Unterschied zu Philip's answer ist, dass die Verantwortlichkeit mehr getrennt sind:

  • Base nichts herleiten, so hat weniger Chancen, verunreinigt wird. Wir ändern nur den Typ seines Datenelements in , das ist es.

  • Nested ist eine reine Typeigenschaft. Es definiert nur Alias ​​type, das ist es.

  • Impl ist eine Implementierungsklasse. Es enthält die Definition der verschachtelten Klasse B oder möglicherweise etwas anderes, das nicht von Base abhängt.


By the way, 4. Auflage von The C++ Programming Language des Stroustrup hat den folgenden Code auf Seite 771:

template<typename N> 
struct Node_base : N::balance_type { }; 

template<typename Val, typename Balance> 
struct Search_node : Node_base<Search_node<Val, Balance> > 
{ 
    using balance_type = Balance; 
}; 

, die genau das gleiche Problem hat.

+0

Danke. Ich werde das verdauen, fortgeschrittene Template-Programmierung ist ein weit entferntes Thema für mich. – NFRCR

6

DIE GESCHICHTE

Wie auf Ihre Frage direkt in den Kommentaren angegeben, was Sie versuchen einfach zu erreichen ist nicht möglich, da es illegal ist, um ein beziehen unvollständiger Typ (die T = A ist innerhalb Base).


DIE Abhilfe

Die gemeinsame Abhilfe in Fällen von CRTP ist ein trait zu verwenden, um Mitglieder zu bezeichnen, die sowohl in Derived und Base zur Verfügung stehen soll, die aber nicht erklärt werden soll/definiert in Base.

Auch wenn dies nicht wirklich gleichbedeutend ist mit dem, was Sie erreichen möchten, ist es sehr nahe daran und folgt einigermaßen äquivalenter Semantik.

template<class> struct some_trait;  // primary template 

template <class T> 
struct A : some_trait<T> {    // (1) 
    typename some_trait<T>::C a; 
}; 

template<> struct some_trait<struct B> { // (2) 
    class C { }; 
}; 

struct B : A<B> {      // (3) 
    C b; 
}; 

int 
main (int argc, char *argv[]) 
{ 
    B a; // legal 
} 

Warum hat die Abhilfe ... ARBEIT?

Um es kurz zu machen; Wir versuchen nicht mehr, auf die Interna eines unvollständigen Typs zuzugreifen.

some_trait<B> ist eine Art direkt nach der Definition (dh. Die Spezialisierung) markiert (2), und aus diesem Grunde kann es durch (1) und (3) ohne irgendwelche Probleme zu verursachen verwendet werden.

+0

Dies [wird nicht kompiliert] (http://coliru.stacked-crooked.com/a/e9cc460456d07316). Sie benötigen 'mit C = typename some_trait :: C;' in 'A'. – iavr

+0

Plus, Struktur 'B' hat jetzt * zwei * Datenelemente vom Typ' C'. – iavr

+0

@iavr Ich habe eigentlich nicht versucht, das Snippet vor dem Posten zu kompilieren, dummer Fehler, ich werde es ändern, um es 100% legal zu machen. –

Verwandte Themen