crtp 和类型可见性

发布于 2024-12-19 22:47:58 字数 2131 浏览 2 评论 0 原文

我有一个正在尝试解决的难题,从根本上来说,它可以归结为以下示例:

template <typename CT>
struct A
{
  typedef typename CT::VALUE_T FOO; // FOO is dependent on CT
};

template <typename CT>
struct B
{
  typedef typename CT::BAR BAR;

  BAR foo() {}
};

template <typename DT>
struct C : B<C<DT> >
{
  typedef DT VALUE_T;

  typedef typename A<C>::FOO BAR;
};

int main () {
  C<int> c;
}

我可以尝试解释上述内容(我已经尝试了大约三次并删除了文本!),但基本上要求是:

  1. < code>C 必须继承自使用 C 键入的 B(利用 CRTP),即 B>
  2. <代码>C是唯一可以实例化 A (即 A 必须用 C 键入)
  3. A 是唯一的可以定义FOOFOO依赖于类型CT,关系比所呈现的更复杂)

问题(如您所见与上面的代码)是 BAR 类型仅可用在 C 中,当实例化 B 时,这是不完整的,因此 B 看不到模板的 BAR 类型参数 CT (C)。不幸的是,在 B 中,类型 BAR 被用作函数的参数和返回类型(即不仅限于函数范围 - 因此我不能简单地将 typedef 移动到功能范围)。

有办法解决这个问题吗?我无法打破上述关系(除非作为最后手段)。大概使用 c++11,我可以使用 auto 并绕过在 B 中使用 BAR typedef 的需要,但这目前不是还有一个选择。

编辑:根据@bitmasks 的评论,提供了一些更多信息。

  1. AB 中的代码在不同情况下用在相当多的二进制文件中,在这种情况下唯一独特的情况是 C 派生自B,在其他实例中,C 拥有从 B 派生的某个实例。
  2. 模板参数可以更改(在 AB 中),只要它们可以默认为不需要更改 A< 的现有使用的值即可。 /code> 和 B。同一组类型必须可用作默认模板参数或某种其他机制。

我在这里使用模板只是因为我需要紧密耦合,并且需要在不同情况下灵活地使用代码。

组件描述:

  • 的 typedef 定义
  • A 最好描述为一个容器,FOO 实际上是一个迭代器,它包含的内容由模板参数B< /code> 最好被描述为一个基类,它包含一组函数,这些函数由 C 实例拥有的某些组件调用。在前面的例子中,这些组件被传递了对从 B 派生的事物的引用(并且这些事物也属于 C),在此例如,我提供了对 C 本身的引用。

主要的复杂性来自于访问容器 A,之前 BC 之间的关系是 C 有一个 B 的实例,但现在 C B 的一个实例 - 此更改语义上打破了类型注入类的方式。

I have this puzzle which I am trying to solve, and fundamentally it boils down to the following example:

template <typename CT>
struct A
{
  typedef typename CT::VALUE_T FOO; // FOO is dependent on CT
};

template <typename CT>
struct B
{
  typedef typename CT::BAR BAR;

  BAR foo() {}
};

template <typename DT>
struct C : B<C<DT> >
{
  typedef DT VALUE_T;

  typedef typename A<C>::FOO BAR;
};

int main () {
  C<int> c;
}

I can try to explain the above (I've tried about three times and deleted the text!), but basically the requirements are:

  1. C must inherit from B typed with C (exploiting CRTP), i.e. B<C<>>
  2. C is the only one that can instantiate A (i.e. A has to be typed with C)
  3. A is the only one that can define FOO (FOO is dependent on the type CT, the relationship is more complicated than that presented)

The problem (as you can see with the above code) is that the BAR type is available only within C and this is incomplete when B is instantiated, hence B does not see the BAR type of the template argument CT (C<int>). Unfortunately within B, the type BAR is used as arguments to functions, and return types (i.e. not just limited to function scope - as a result I cannot simply move the typedef to function scope).

Is there a way around this? I cannot break the above stated relationships (unless as a last resort). Presumably with c++11, I could use auto and get around the need to have the BAR typedef in B, however this is currently not yet an option.

EDIT: following on from @bitmasks' comment, some more information.

  1. The code in A and B is used in quite a few binaries in different situations, the only unique situation in this case is that C derives from B, in the other instances, C owns an instance of something derived from B.
  2. The template arguments can be changed (in A and B), as long as they can be defaulted to values which doesn't require changing existing uses of A and B. The same set of types must be available either as template parameter that is defaulted or some other mechanism.

I'm using templates here simply because I require the tight-coupling and I needed the flexibility to use the code in different situations.

Descriptions of components:

  • A is best described as a container, and FOO really is an iterator, what it contains is defined by a typedef of the template parameter
  • B is best described as a base class which contains a set of functions which are called by some components owned by an instance of C. In the previous cases, those components were passed a reference to things derived from B (and those things are also owned by C), in this instance, I'm providing a reference to C itself.

The main complication arises from accessing the container A, previously the relationship between B and C is that C has an instance of B, but now C is an instance of B - this change in semantics breaks the way types are injected into the classes.

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

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

发布评论

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

评论(1

羞稚 2024-12-26 22:47:58

我认为您可以使用默认模板参数来应对循环 typedef 要求。以下内容按预期工作(据我理解您的问题),并为您(几乎)保留了原始代码的所有自由:

template <typename CT, typename CTVALUE_T = typename CT::VALUE_T>
struct A
{
    //typedef typename CT::VALUE_T FOO; // FOO is dependent on CT
    typedef CTVALUE_T FOO; // FOO is dependent on CT
};

template <typename CT, typename CTBAR = typename CT::BAR>
struct B
{
    //typedef typename CT::BAR BAR;
    typedef CTBAR BAR;

    BAR foo() {return 0;}
};

template <typename DT> struct VALUE_T__from__DT {
  typedef DT VALUE_T;
};

template <typename DT, template <class T> class _C_ > struct BAR__from__DT {
  typedef typename A<_C_<DT> , typename VALUE_T__from__DT<DT>::VALUE_T >::FOO BAR;
};

template <typename DT>
struct C : B<C<DT>, typename BAR__from__DT<DT, C >::BAR >
{
    //typedef DT VALUE_T;

    //typedef typename A<C>::FOO BAR;
};

int main () {
    C<int> c;
    int x = c.foo();
    (void)x;
    return 0;
}

帮助器模板类型的名称很糟糕,也许您可​​以找到更好的名称。

核心技巧是有问题的 typedef 的定义被放入一个单独的元容器(即特征容器)中,这样您仍然可以在那里进行任何巫术。

我注释掉了不必要的 typedef(但将它们留在那里,以便您有更好的机会弄清楚我在那里做什么)。

这符合您的需要吗?

I think you can combat the cyclic typedef requirement with default template parameters. The following works as intended (as far as I understand your question) and leaves you (almost) all the liberties of your original code:

template <typename CT, typename CTVALUE_T = typename CT::VALUE_T>
struct A
{
    //typedef typename CT::VALUE_T FOO; // FOO is dependent on CT
    typedef CTVALUE_T FOO; // FOO is dependent on CT
};

template <typename CT, typename CTBAR = typename CT::BAR>
struct B
{
    //typedef typename CT::BAR BAR;
    typedef CTBAR BAR;

    BAR foo() {return 0;}
};

template <typename DT> struct VALUE_T__from__DT {
  typedef DT VALUE_T;
};

template <typename DT, template <class T> class _C_ > struct BAR__from__DT {
  typedef typename A<_C_<DT> , typename VALUE_T__from__DT<DT>::VALUE_T >::FOO BAR;
};

template <typename DT>
struct C : B<C<DT>, typename BAR__from__DT<DT, C >::BAR >
{
    //typedef DT VALUE_T;

    //typedef typename A<C>::FOO BAR;
};

int main () {
    C<int> c;
    int x = c.foo();
    (void)x;
    return 0;
}

The names of the helper template types are horrible, perhaps you can find better names.

The core trick is that the definition of the problematic typedefs is put in a separate meta-container (i.e. a container for traits) such that you can still do any voodoo there.

I commented the unnecessary typedefs out (but left them there so you have a better chance to figure out what I'm doing there).

Does that fit your need?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文