如何在编译时私有时获取成员的偏移量?

时间:2014-03-07 06:51:06

标签: c++ templates linked-list doubly-linked-list

我有一个链表类,它使用宏来获取对象中节点成员的偏移量。抛开offsetof()是否保证适用于所有数据类型的问题,是否有人能想到在编译时获得此偏移并且仍允许数据成员保密的方法?我花了一些时间无处模板并研究了boost :: instrusive源代码,但它们似乎在运行时得到了偏移量(虽然我不确定,代码很难导航)这是不可接受的在这种情况下。

我已经尝试过朋友/模板帮助程序类,但却看不到这样做的方法。

另一种方法是以某种方式在列表模板声明中指定子节点,并在getnode()中使用offsetof(),但我无法弄清楚它是如何完成的,我的模板fu不够强大。是否可以使用指向成员的模板参数类型?

来完成

这说明了问题,它不应该编译......

// mylist.h

#include <cstddef>

struct node
{
    node *prev;
    node *next;
};

template <typename T, size_t o> struct list
{
    static node *getnode(T *obj)
    {
        return reinterpret_cast<node *>(reinterpret_cast<char *>(obj) + o);
    }

    node root;

    list()
    {
        root.next = root.prev = &root;
    }

    void addtail(T *object)
    {
        node *n = getnode(object);
        n->prev = root.prev;
        n->next = &root;
        root.prev->next = n;
        root.prev = n;
    }

    // etc...
}

#define linked_list(str, node) list<name, offsetof(str, node)>

// test.cpp

struct foo
{
    int i;

private:
    node m_node;
};

linked_list(foo, m_node) mylist;    // error, m_node is private...

2 个答案:

答案 0 :(得分:1)

是否要求您按照自己的方式设计列表?因为这不是处理列表的常用方法。

常见的方法是拥有一个包含实际数据的私有节点结构。像

这样的东西
template<typename T>
class List
{
    struct node
    {
        node* next;
        node* prev;
        T     data;  // Data store in the node
    }

    node* list;  // The actual list

public:
    // ...

    void AddHead(const T& data)
    {
        node* n = new node;
        n->data = data;

        // ...
    }

    // ...
};

像这样使用:

struct foo
{
    int i;
};

List<foo> myList;

foo myFoo;
myList.AddHead(myFoo);

使用此设计,您甚至不需要结构来存储基本类型,例如int

List<int> myIntegerList;
myList.AddHead(5);

答案 1 :(得分:0)

使用reinterpret_cast已经是红鲱鱼,当然也是offsetof

您是否考虑过:

class Node {
    template <typename T> friend class List;
    Node* prev = nullptr;
    Node* next = nullptr;
}; // class Node

template <typename T>
class List {
public:
    void push_back(T& object)
    {
        Node& n = getnode(object);
        n.prev = root.prev;
        n.next = &root;
        root.prev->next = &n;
        root.prev = &n;
    }
private:
    Node root;
}; // class List
简单,不是吗?现在:

class Foo {
public:
    friend Node& getnode(Foo& foo) { return foo.node; }

private:
    int payload;
    Node node;
}; // class Foo

它编译,尊重隐私see here,但崩溃(因为push_back错误,我会让你解决这个问题。)


这是给定对象中多个节点的实现:

class Node {
    template <typename, size_t> friend class List;
    Node* prev = nullptr;
    Node* next = nullptr;
}; // class Node

template <typename T, size_t Index>
class List {
public:
    void push_back(T& object)
    {
        Node& n = getnode(object, std::integral_constant<size_t, Index>{});
        n.prev = root.prev;
        n.next = &root;
        root.prev->next = &n;
        root.prev = &n;
    }
private:
    Node root;
}; // class List

使用用户类:

class Foo {
public:
    friend Node& getnode(Foo& foo, std::integral_constant<size_t, 0>) {
        return foo.node;
    }

explicit Foo(int p = 0): payload(p) {}
private:
    int payload;
    Node node;
}; // class Foo