2010-04-01 4 views
9

Je tente d'écrire une classe hôte basée sur des règles (c'est-à-dire une classe qui hérite de sa classe modèle), avec une torsion, où la classe de stratégie est également modélisée par le classe hôte, de sorte qu'il peut accéder à ses types. Un exemple où cela peut être utile est où une politique (utilisée comme un mixin, vraiment), augmente la classe hôte avec une méthode clonée polymorphique(). Voici un exemple minimal de ce que je suis en train de faire:Mélange de la conception basée sur des règles avec CRTP en 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; 
} 

Cela, malheureusement, ne parvient pas à compiler, ce qui me semble comme la dépendance de type circulaire:

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

Si quelqu'un peut repérer une erreur évidente, ou a réussi à mélanger CRTP dans les politiques, j'apprécierais toute aide.

Répondre

6

En fait, le problème est dû à HostPtr déclaration n'ayant pas encore vu lorsque vous héritez de la politique. Il y a une discussion sur la sémantique exacte où ces déclarations sont visibles par les modèles instanciés, ce qui pose des problèmes assez complexes, voir this defect report.

Mais dans votre cas, la situation est claire: Avant le corps de la classe, aucun code ne peut voir une déclaration des membres de classe, et donc votre code échoue. Vous pouvez passer le type comme argument de modèle

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

S'il y a plus de types, vous pouvez décider de passer un trait

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