16

编辑:当我为任何感兴趣的人改变我的设计时,我会在这里放一个 github 链接。

背景

我正在用我自己的实现替换boost::intrusive, intrusive_set,因为 64 位编译的侵入集将 3 x 8 字节的指针填充到我的容器节点中。我的容器有 2^16 个节点的限制,因此我可以使用 2x 16 位偏移序数将其降低到每个节点 4 字节(大小减少 6 倍)。

在下面的示例中base是 intrusive-set 容器。该类derived有一个std::vector<container_entry_type<entry_type> >. 显然,在这种间接级别下,我需要在派生中拥有一堆嵌套的 typedef,我想在 base.xml 中引用它们。

ps,容器用于数据描述语言的AST。因此,包含的元素是小型数据类型,并且 3 x 8 字节非常重要。尤其是因为容器用于在紧密循环中验证数据集。

孤立的问题

我想实现以下语义:

template<typename TWO>
class base
{
public:
  void foo(typename TWO::dummy & d);
};

template<typename DUMMY>
class derived
  : private base< derived<DUMMY> >
{
public:
  typedef DUMMY dummy;
};

struct tag{};

int main()
{
  derived<tag> foo;
}

但我无法从基础访问嵌套的 typedef。对于这件事,clang 是这么说的:

main.cc: In instantiation of ‘base<derived<tag> >’:
main.cc:9:7:   instantiated from ‘derived<tag>’
main.cc:20:16:   instantiated from here
main.cc:5:8: error: no type named ‘dummy’ in ‘class derived<tag>’

相反,我必须这样做:

template<typename type_key>
class traits
{
public:
  typedef type_key dummy;
};

template<typename TWO, typename type_key>
class base
{ 
public:
  void foo(typename traits<type_key>::dummy & d);
};

template<typename DUMMY>
class derived
  : private base< derived<DUMMY>, DUMMY >
{
public:
  typedef DUMMY dummy;
};

struct tag{};

int main()
{
  derived<tag> foo;
}

这是实现我的用例的唯一方法吗?它只会让事情变得更加冗长。我想派生也可以从特征派生以节省一些击键。

另一种选择是不使用推导并将逻辑直接连接到当前推导的内容中。但是,我想单独对基础进行单元测试。

4

3 回答 3

10

另一种可能性(可能会或可能不会节省您的击键)是在某些地方不使用派生类在父类中的嵌套类型。例如。代替

void foo(typename TWO::dummy & d);

你会用

template <class T>
void foo(typename T& d);

对于额外的点,您可以使用 SFINAE 来实际限制T原始变体允许的类型。(请注意,在嵌套模板中,TWO::dummy可以自由使用 - 它们仅在整个事物(包括)之后derived才被实例化,所以它可以解决。在天真的版本中,在使用其成员函数derived实例化时仍然不完整,它base没有::dummy,这就是它失败的原因)

于 2011-11-13T19:13:44.150 回答
5

扩展@jpalecek的想法,我们可以使该模板参数采用默认参数。但是你需要启用 C++0x 才能得到这个

#include <typeinfo>
#include <cstdio>

template<typename TWO>
class base
{
public:
    template <typename X = TWO>   // <-- (requires C++0x to have a default)
    void foo(typename X::dummy& d)
    {
        printf("%s\n", typeid(d).name());
    }
};

template<typename DUMMY>
class derived
  : public base< derived<DUMMY> >
{
public:
  typedef DUMMY dummy;
};

struct tag{};

int main()
{
  derived<tag> foo;
  tag t;
  foo.foo(t);       // <--- call the function like normal.
}

http://ideone.com/AXXdW

于 2011-11-13T19:18:02.427 回答
1

不需要traits上课。您可以type_key直接在base.

但是,您不能避免将类型显式传递给base. 在base实例化的时候,derived编译器还没有看到 typedef (更准确地说:这个类derived还没有完成——它怎么可能呢,因为它的基类还不存在)。

于 2011-11-13T19:15:09.527 回答