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