2010-04-01 9 views
9

Sto tentando di scrivere una classe host basata su criteri (ovvero una classe che eredita dalla sua classe template), con una svolta, in cui la classe della politica è anche rappresentata dal classe host, in modo che possa accedere ai suoi tipi. Un esempio in cui ciò potrebbe essere utile è dove un criterio (utilizzato come un mixin, in realtà), aumenta la classe host con un metodo clone() polimorfico. Ecco un esempio minimo di quello che sto cercando di fare:Miscelazione del design basato su criteri con 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; 
} 

Questo, purtroppo, non riesce a compilare, in quello che sembra a me come tipo circolare dipendenza:

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>’ 

Se qualcuno può individuare un ovvio errore, o ha riuscito a mescolare CRTP in politiche, gradirei qualsiasi aiuto.

risposta

6

In realtà il problema è dovuto alla dichiarazione HostPtr che non si è ancora vista quando si eredita dalla politica. C'è una discussione sulla semantica esatta in cui queste dichiarazioni sono visibili da modelli istanziati, che ha problemi piuttosto complessi, vedere this defect report.

Ma nel tuo caso, la situazione è chiara: prima del corpo della classe, nessun codice può vedere alcuna dichiarazione dei membri della classe, e quindi il tuo codice fallisce. Si potrebbe passare il tipo come argomento di modello

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)); 
    } 
}; 

Se ci sono più tipi, si può decidere di passare un tratto

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)); 
    } 
};