1

假设我想写一个侵入性列表。我有一个侵入式列表类模板,它采用类型和指向成员的指针以用作节点。它看起来大致是这样的:

// This needs to be a member of anything the intrusive list is going to store.
class IntrusiveListNode {
    // ...
}

// The intrusive list itself
template <class T, IntrusiveListNode T::*Member>
class IntrusiveList {
    // ...
};

// This is a type that is going to be stored in an intrusive list.
class IntegerListNode {
public:
    IntrusiveListNode node;

private:
    int value;
};

// An example of the how the list would be used.
IntrusiveList<IntegerListNode, &IntegerListNode::node> myList;

您要存储在列表中的每件事都有一个 IntrusiveListNode 。要将 IntrusiveListNode 变回您可以使用的东西,例如 IntegerListNode,您需要调用一个函数,该函数根据节点在类中的偏移量对节点进行一些指针运算,然后将其转换为适当的类型。这似乎有效,但我认为不能保证。

我希望能够在我的类中添加一个 static_assert,以在编译时验证您使用的类型是安全的,但我不确定 static_assert 的条件是什么。我认为这只有在持有 IntrusiveListNode 的类型是标准布局类时才能保证有效,但我不确定,因为标准布局类型的要求似乎比我实际需要的更严格。

特别是,标准布局类型要求所有成员具有相同的访问控制。我需要的是能够确保指针算术能够正常工作。这意味着您不能在多态类型上使用它,因为结构的两个不同版本可能会以不同方式布局,但如果该类型混合了私有和公共数据成员,这应该不是问题,对吧?如果我只要求类型是非多态的,那会安全吗?还是有更好的检查方法?还是我卡在做is_standard_layout检查?

4

1 回答 1

1

我不能引用这个标准(我很确定这是未定义的行为领域),但您通常可以依赖数据成员相对于指向包含类的指针的偏移量的一致性,前提是静态此指针的类型是常量(在您的情况下为 IntegerListNode*)。

您可能会发现偏移量在相对于派生类型的指针进行测量时会发生变化,但只要您总是先将其重新解释为 IntegerListNode ,然后再将静态/动态转换为派生类型(如果需要),我几乎会觉得很舒服:)

这并不是说这是一个好主意。实现侵入式列表不需要这种指针算法。如果您只是在 IntegerListNode 中定义一个“下一个”和/或“上一个”指针(指向一个 IntegerListNode),您可以将一个指向成员的指针传递给 IntrusiveList,并且永远不需要创造性转换:)

于 2015-05-26T06:03:24.977 回答