2016-04-08 8 views
1

Ich habe ein paar Klassen (A, , C) jeweils mit einem Mitglied mit einem Templat (Ptr<...>) Typ je nach dem unvollständigen Typ einer anderen Klasse (rund). Ich würde gerne die Typen eingeben (::ptr) wie unten gezeigt. Dies scheint nicht zu funktionieren - mein Compiler sagt mir folgendes:Typedefs in circular-abhängigen Klassen

In file included from B.hpp:6:0, 
       from A.hpp:6: 
C.hpp:13:8: error: ‘ptr’ in ‘class A’ does not name a type 
    A::ptr a; 
     ^

jedoch T* statt T::ptr macht es funktioniert. Wie kann ich das beheben?

A.hpp:

#ifndef TEST_INCLUDE_A 
#define TEST_INCLUDE_A 1 

class A; 

#include "B.hpp" 

#include "P.hpp" 

class A { 
public: 
    typedef Ptr<A> ptr; 
    B::ptr b; 
}; 

#endif 

B.hpp:

#ifndef TEST_INCLUDE_B 
#define TEST_INCLUDE_B 1 

class B; 

#include "C.hpp" 

#include "P.hpp" 

class B { 
public: 
    typedef Ptr<B> ptr; 
    C::ptr c; 
}; 

#endif 

C.hpp:

#ifndef TEST_INCLUDE_C 
#define TEST_INCLUDE_C 1 

class C; 

#include "A.hpp" 

#include "P.hpp" 

class C { 
public: 
    typedef Ptr<C> ptr; 
    A::ptr a; 
}; 

#endif 

P.hpp:

#ifndef TEST_INCLUDE_PTR 
#define TEST_INCLUDE_PTR 1 

template<class T> 
class Ptr { 
public: 
    T* ptr_t; 
}; 

#endif 

Antwort

2

Für die Zwecke der zirkuläre Abhängigkeit zu lösen, Sie gehen nur einer Hand halten den Compiler zu geben und einige Vorkenntnis zu vermitteln, was ptr in der anderen Klasse sein wird, das heißt: Sie wissen, dass A::ptr ist Ptr<A>, und so weiter.

online demo

class A; 
class B; 

template<typename T> 
struct Ptr { T* ptr_t; }; 

class A { 
public: 
    using ptr = Ptr<A>; 
    Ptr<B> b; 
}; 

class B { 
public: 
    using ptr = Ptr<B>; 
    Ptr<A> a; 
}; 

int main() { 
    A a; 
    B b; 
    a.b.ptr_t = &b; 
    b.a.ptr_t = &a; 

    A::ptr aptr; 
    B::ptr bptr; 
    aptr.ptr_t = &a; 
    bptr.ptr_t = &b; 
    a.b = bptr; 
    b.a = aptr; 
} 
1

Es gibt bestimmte Operationen, die Sie nur für einen vollständigen Typ ausführen können. Einer von ihnen ist, von [basic.def.odr]:

Ein Klassentyp T muss vollständig sein, wenn:
- [...]
- ein Klassenmitglied Zugriffsoperator auf einen Ausdruck angewandt wird vom Typ T (5.2.5) oder
- [...]

Schreiben A::ptr erfordert A auf Vollständigkeit. A ist nicht vollständig an dem Punkt, an dem wir C definieren, dies ist also ein Fehler.

Auf der anderen Seite, wenn Sie A* jedoch schreiben, dass nicht erforderlich machen A auf Vollständigkeit. Es ist in Ordnung, Zeiger (oder Referenzen) auf unvollständige Typen als Mitglieder zu haben.

1

Mein Vorschlag:

  1. Aktualisieren Sie die Definition von P leicht eine abgeleitete Typnamen zu definieren.

    template<class T> 
    class Ptr { 
    public: 
        using ptr_t = T*; 
        ptr_t ptr; 
    }; 
    
  2. aktualisieren A.hpp, B.hpp und C.hpp verlassen nur auf Vorwärtserklärungen B, C und A sind.

    Die aktualisierte Version von A.hpp.

    #ifndef TEST_INCLUDE_A 
    #define TEST_INCLUDE_A 1 
    
    #include "P.hpp" 
    
    class B; 
    
    class A { 
        public: 
         typedef Ptr<A> ptr; // This does not seem useful any longer 
              // It can probably be removed. 
         Ptr<B> b_ptr; 
    }; 
    
    #endif 
    

    Update B.hpp und C.hpp ähnlich.

Verwandte Themen