2010-04-01 2 views
9

Я пытаюсь написать класс хоста на основе политик (то есть класс, который наследуется от его класса шаблонов), с твистом, где класс политики также шаблонизируется хост-класс, чтобы он мог получить доступ к своим типам. Одним из примеров, где это может быть полезно, является то, где политика (используемая как mixin, действительно), увеличивает класс хоста с помощью метода polyorphic clone(). Вот минимальный пример того, что я пытаюсь сделать:Смешивание политик на основе политик с использованием CRTP в 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; 
} 

Это, к сожалению, не в состоянии собрать, в том, что мне кажется, как круговой тип зависимости:

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

Если кто-то может Пятно очевидная ошибка или успешно смешивает CRTP в политике, я был бы признателен за любую помощь.

ответ

6

На самом деле проблема заключается в том, что объявление HostPtr еще не увидело, когда вы наследуете политику. Существует некоторая дискуссия о точной семантике, где эти объявления видны с помощью созданных шаблонов, что имеет довольно сложные проблемы, см. this defect report.

Но в вашем случае ситуация ясна: перед телом класса ни один код не может видеть никакого объявления членов класса, поэтому ваш код выходит из строя. Вы можете передать тип в качестве аргумента шаблона

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

Если есть несколько типов, вы можете решить, чтобы пройти черту

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