2010-04-01 13 views
9

Ich versuche, eine richtlinienbasierte Host-Klasse zu schreiben (dh eine Klasse, die von ihrer Template-Klasse erbt), mit einer Wendung, wo die Policy-Klasse auch von der Templates Host-Klasse, damit sie auf ihre Typen zugreifen kann. Ein Beispiel, wo dies nützlich sein könnte, ist, wo eine Richtlinie (die wirklich wie ein Mixin verwendet wird) die Host-Klasse um eine polymorphe clone() -Methode erweitert. Hier ist ein minimales Beispiel dafür, was ich versuche zu tun:Mischen von richtlinienbasiertem Design mit CRTP in C++

template <template <class> class P> 
struct Host : public P<Host<P> > { 
    typedef P<Host<P> > Base; 
    typedef Host* HostPtr; 
    Host(const Base& p) : Base(p) {} 
}; 

template <class H> 
struct Policy { 
    typedef typename H::HostPtr Hptr; 
    Hptr clone() const { 
    return Hptr(new H((Hptr)this)); 
    } 
}; 

Policy<Host<Policy> > p; 
Host<Policy> h(p); 

int main() { 
    return 0; 
} 

Dies ist leider zu kompilieren fehlschlägt, in dem, was ich scheint, wie Kreis Typen Abhängigkeit:

try.cpp: In instantiation of ‘Host<Policy>’: 
try.cpp:10: instantiated from ‘Policy<Host<Policy> >’ 
try.cpp:16: instantiated from here 
try.cpp:2: error: invalid use of incomplete type ‘struct Policy<Host<Policy> >’ 
try.cpp:9: error: declaration of ‘struct Policy<Host<Policy> >’ 
try.cpp: In constructor ‘Host<P>::Host(const P<Host<P> >&) [with P = Policy]’: 
try.cpp:17: instantiated from here 
try.cpp:5: error: type ‘Policy<Host<Policy> >’ is not a direct base of ‘Host<Policy>’ 

Wenn jemand eine beschmutzen können offensichtlicher Fehler, oder hat CRTP in Richtlinien erfolgreich gemischt, würde ich jede Hilfe schätzen.

Antwort

6

In der Tat ist das Problem aufgrund HostPtr Erklärung noch nicht gesehen, wenn Sie von der Richtlinie erben. Es gibt einige Diskussionen über die genaue Semantik, wo diese Deklarationen von instanziierten Vorlagen sichtbar sind, was ziemlich komplexe Probleme hat, siehe this defect report.

Aber in Ihrem Fall ist die Situation klar: Vor dem Klassenkörper kann kein Code eine Deklaration von Klassenmitgliedern sehen und Ihr Code schlägt fehl. Sie könnten den Typ als Vorlage Argument übergeben

template <template <class,class> class P> 
struct Host : public P<Host<P>, Host<P>* > { 
    typedef P<Host<P> > Base; 
    Host(const Base& p) : Base(p) {} 
}; 

template <class H, class Hptr> 
struct Policy { 
    typedef Hptr HostPtr; 
    HostPtr clone() const { 
    return Hptr(new H((Hptr)this)); 
    } 
}; 

Wenn es mehr Arten sind, können Sie ein Merkmal

template <class Host> 
struct HTraits { 
    typedef Host *HostPtr; 
    // ... 
}; 

template <template <class,class> class P> 
struct Host : public P<Host<P>, HTraits< Host<P> > > { 
    typedef P<Host<P> > Base; 
    Host(const Base& p) : Base(p) {} 
}; 

template <class H, class Htraits> 
struct Policy { 
    typedef typename Htraits::HostPtr HostPtr; 
    HostPtr clone() const { 
    return Hptr(new H((Hptr)this)); 
    } 
}; 
passieren entscheiden