Смешивание основанного на политике дизайна с 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 в политиках, я ценил бы любую справку.

9
задан Eitan 1 April 2010 в 04:25
поделиться

1 ответ

На самом деле проблема связана с тем, что объявление 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));
  }
};
7
ответ дан 4 December 2019 в 23:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: