Смешивание основанного на политике дизайна с CRTP в C ++ - PullRequest
9 голосов
/ 01 апреля 2010

Я пытаюсь написать основанный на политике хост-класс (т. Е. Класс, который наследуется от своего шаблонного класса), с завихрением, где класс политики также шаблонизируется хост-классом, чтобы он мог получить доступ к своему типы. Один из примеров, где это может быть полезно, - это когда политика (на самом деле используемая как mixin) дополняет класс хоста полиморфным методом clone (). Вот минимальный пример того, что я пытаюсь сделать:

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 в политиках, я был бы признателен за любую помощь.

1 Ответ

7 голосов
/ 11 апреля 2010

На самом деле проблема в том, что объявление 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));
  }
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...