在 C++ 中将基于策略的设计与 CRTP 混合在一起

发布于 2024-08-26 23:50:00 字数 1274 浏览 9 评论 0原文

我正在尝试编写一个基于策略的主机类(即从其模板类继承的类),但有一点不同,其中策略类也由主机类模板化,以便它可以访问其类型。这可能有用的一个例子是,策略(实际上像 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,我将不胜感激任何帮助。

I'm attempting to write a policy-based host class (i.e., a class that inherits from its template class), with a twist, where the policy class is also templated by the host class, so that it can access its types. One example where this might be useful is where a policy (used like a mixin, really), augments the host class with a polymorphic clone() method. Here's a minimal example of what I'm trying to do:

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

This, unfortunately, fails to compile, in what seems to me like circular type dependency:

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

If anyone can spot an obvious mistake, or has successfuly mixing CRTP in policies, I would appreciate any help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

像你 2024-09-02 23:50:00

事实上,问题是由于当您从策略继承时尚未看到 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));
  }
};

In fact the problem is due to HostPtr declaration not having seen yet when you inherit from the policy. There is some discussion about the exact semantics where these declarations are visible by instantiated templates, which has pretty complex issues, see this defect report.

But in your case, the situation is clear: Before the class body, no code can see any declaration of class members, and so your code fails. You could pass the type as a template argument

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

If there are more types, you may decide to pass a 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));
  }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文