C++ CRTP 和从基访问派生的嵌套类型定义

发布于 2024-12-15 06:55:46 字数 1796 浏览 1 评论 0 原文

编辑:当我完成对任何感兴趣的人的设计更改后,我将在此处放置一个 github 链接。

背景

我正在用我自己的 64 位编译侵入集内容 3 x 8 的实现替换 boost::intrusiveintrusive_set -byte 指向我的容器节点的指针。我的容器有 2^16 个节点的限制,因此我可以将每个节点的大小减少到 4 个字节,并使用 2x 16 位偏移序号(大小减少了 6 倍)。

在下面的示例中,base 是侵入集容器。 衍生类有一个std::vector >。显然,对于这种间接级别,我需要在派生中拥有一堆嵌套的 typedef,我想在基类中引用它们。

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

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

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

edit: I'll put a github link here when I am done altering my design for anyone who is interested.

Background

I'm replacing a boost::intrusive, intrusive_set, with my own implementation as 64-bit compiled intrusive-set stuffs 3 x 8-byte pointers into my container nodes. my container has a limit of 2^16 nodes so I can bring it down to 4-bytes per node with 2x 16-bit offset ordinals (which is a 6x reduction of size).

In the example below base is the intrusive-set container. The derived class has a std::vector<container_entry_type<entry_type> >. obviously with this level of indirection I need to have a bunch of nested typedef's in derived, which I'd like to refer to in base.

p.s., the containers are for the AST of data description language. The contained elements are therefore small data types and 3 x 8-bytes is very significant. Especially so since the containers are used to validate data-sets in tight loops.

The problem isolated

I want to achieve the following semantics:

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

But I can't access the nested typedef from the base. This is what clang has to say about the matter:

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

Instead I am having to do:

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

Is this the only way to achieve my use-case ? it just makes things a whole lot more verbose. I suppose derived could also derive from traits to save some keystrokes.

Another choice is to not use derivation and to wire the logic straight into what is currently derived. However, I'd like to individually unit test base.

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

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

发布评论

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

评论(3

墨落画卷 2024-12-22 06:55:46

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

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

使用

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

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

Another possibility (that might or might not save you keystrokes) would be not using the derived classes' nested types in the parent in some places. Eg. instead of

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

you'd use

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

For extra points, you could use SFINAE to actually limit T to the types permissible for the original variant. (Note that inside nested templates, TWO::dummy can be used freely - they are only instantiated after the whole thing incl. derived has been, so it works out. In the naive version, derived is still incomplete at the point of instantiating the base with its member functions, it has no ::dummy, which is why it fails)

独木成林 2024-12-22 06:55:46

扩展 @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

Extending @jpalecek's idea, we could make that template argument take a default argument. But you need to enable C++0x to get this

#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

方圜几里 2024-12-22 06:55:46

不需要 traits 类。您可以直接在 base 中使用 type_key

但是,您无法避免将类型显式传递给base。在实例化 base 时,编译器还没有看到 provider 中的 typedef(更准确地说:类 provider 还没有被编译器识别)。完整——怎么可能呢,因为甚至它的基类还不存在)。

There's no need for the traits class. You can just use type_key directly in base.

You cannot, however, avoid passing the type explicitly to base. At the time base is instantiated, the typedef in derived has not yet been seen by the compiler (more exactly: the class derived is not yet complete — how could it, given that even its base class doesn't exist yet).

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