C++ CRTP并从base访问派生的嵌套typedef

Has*_*yed 16 c++ boost crtp intrusive-containers

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

背景

我更换boost::intrusive,intrusive_set与我自己的实现为64位编译侵入设定的东西3×8个字节的指针到我的容器节点.我的容器有2 ^ 16个节点的限制,所以我可以将它降低到每个节点4个字节,带有2个16位偏移序数(大小减少6倍).

在下面的示例中base是侵入式集合容器.该derived班有一个std::vector<container_entry_type<entry_type> >.显然,对于这种间接级别,我需要在派生中有一堆嵌套的typedef,我想在base中引用它.

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;
}
Run Code Online (Sandbox Code Playgroud)

但我无法从基础访问嵌套的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>’
Run Code Online (Sandbox Code Playgroud)

相反,我必须这样做:

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;
}
Run Code Online (Sandbox Code Playgroud)

这是实现我的用例的唯一方法吗?它只是让事情变得更加冗长.我认为派生也可以从特征中导出来保存一些击键.

另一个选择是不使用派生并将逻辑直接连接到当前派生的内容.但是,我想单独测试基地.

jpa*_*cek 10

另一种可能性(可能会或可能不会保存击键)在某些地方不会在父级中使用派生类的嵌套类型.例如.代替

void foo(typename TWO::dummy & d);
Run Code Online (Sandbox Code Playgroud)

你会用的

template <class T>
void foo(typename T& d);
Run Code Online (Sandbox Code Playgroud)

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


ken*_*ytm 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.
}
Run Code Online (Sandbox Code Playgroud)

http://ideone.com/AXXdW