我正在尝试将内部列表定义为具有类型安全container_of成员函数的模板类。为此,模板必须包括容器的类型以及在容器中找到列表的位置(成员指针)。(有关 C 语言中的示例,请参见下文)。
它应该是这样的:
template <class T, List * T::*MEMBER> class List { ... }
但在<>中,尚未定义 List 类型,因此无法使用。我的下一个尝试是:
template <class T, class L, L * T::*MEMBER> class List { ... };
class Container {
List<Container, List<???>, Container::list> list;
};
但是"???"放什么呢?那必须是整个<>,包括???.所以你会得到一个无休止的递归。
接下来,我试图在类型安全上作弊:
template <class T, void * T::*M>
class List {
public:
T * container_of() {
return (T *)(intptr_t(this) - intptr_t(&((T *)NULL)->M));
}
};
class Container {
public:
List<Container, Container::item1> item1;
};
但这给了我:
error: incomplete type 'Container' used in nested name specifier
List<Container, Container::item1> item1;
^
使用 C 预处理器 makros 我想要的看起来像这样:
#include <unistd.h> // for NULL
#include <stdint.h> // for intptr_t
#include <iostream>
#define LIST(TYPE, MEMBER)
class List_ ## MEMBER ## _t {
public:
TYPE * container_of() {
return (TYPE *)(intptr_t(this) - intptr_t(&((TYPE *)NULL)->MEMBER));
}
} MEMBER
class Container {
public:
LIST(Container, item1);
LIST(Container, item2);
};
int main() {
Container c;
std::cout << "Container at " << &c << std::endl;
std::cout << "Container of item1 = " << c.item1.container_of() << std::endl;
std::cout << "Container of item2 = " << c.item2.container_of() << std::endl;
}
那么这可以用模板来表达吗?
我找到了解决方案。它不是100%完美,但很接近。
这个想法是有 3 个类:
class Item;
template <class T, Item T::*M> class Iterator;
template <class T, Item T::*M> class Head;
Item 类包含构成内存中实际列表的下一个/上一个链接。这不包括容器类型和列表在容器内的位置,并且(本身)是不安全的。但是 Item 没有修改列表的方法。所有修改都是通过迭代器完成的。甚至构造也是使用 Head 来获取迭代器并初始化下一个/上一个指针来完成的。
迭代器类可以从容器 T 构造,并具有运算符 ++,--, == 和 !=,可以将容器插入当前位置或将容器移动到另一个迭代器后面到它自己的列表中。迭代器还有运算符 *,它返回当前容器和运算符 bool 来表示是否已到达列表的末尾。
Head 类包含一个特殊的头和尾项,分别具有 prev==NULL 和 next==NULL 。它们很特别,因为它们不在容器 T 的实例中,并标记列表的开头和结尾。除了按住结束标记之外,Head 还提供了创建指向头部、尾部、第一个和最后一个元素的迭代器的方法。这允许迭代列表或在开头或结尾插入。
有一个 4th 类 ConstIterator,它类似于 Iterator,但用于 const 访问。
注意:这只是最低限度的测试。其余错误留给读者修复。
class Item;
template <class T, Item T::*M> class Iterator;
template <class T, Item T::*M> class ConstIterator;
template <class T, Item T::*M> class Head;
template<class T, Item T::*M>
T * container_of(Item *item) {
return (T *)(intptr_t(item) - intptr_t(&(((T *)NULL)->*M)));
}
template<class T, Item T::*M>
const T * container_of(const Item *item) {
return (const T *)(intptr_t(item) - intptr_t(&(((const T *)NULL)->*M)));
}
class Item {
public:
template <class T, Item T::*M> Item(Head<T, M> *head, T *container) {
assert((container_of<T, M>(this)) == container);
head->tail().insert_before(container);
}
~Item() {
if (next_) next_->prev_ = prev_;
if (prev_) prev_->next_ = next_;
next_ = NULL;
prev_ = NULL;
}
private:
template <class T, Item T::*M> friend class Iterator;
template <class T, Item T::*M> friend class ConstIterator;
template <class T, Item T::*M> friend class Head;
Item(Item *next__, Item *prev__) : next_(next__), prev_(prev__) { }
Item(const Item &) = delete;
Item & operator =(const Item &) = delete;
Item *next_;
Item *prev_;
};
template <class T, Item T::*M>
class Iterator {
public:
Iterator() : item_(NULL) { }
Iterator(T *container) : item_(&(container->*M)) { }
~Iterator() { }
operator bool() const {
assert(item_);
// not head and not tail
return ((item_->next_ != NULL) && (item_->prev_ != NULL));
}
T & operator *() {
assert(item_);
if ((item_->next_ == NULL) || (item_->prev_ == NULL)) {
// head or tail has no container
assert(false);
}
return *container_of<T, M>(item_);
}
T & operator ->() {
assert(item_);
if ((item_->next_ == NULL) || (item_->prev_ == NULL)) {
// head or tail has no container
assert(false);
}
return *container_of<T, M>(item_);
}
Iterator & operator ++() {
assert(item_);
assert(item_->next_);
item_ = item_->next_;
return *this;
}
Iterator & operator --() {
assert(item_);
assert(item_->prev_);
item_ = item_->prev_;
return *this;
}
bool operator ==(const Iterator &other) {
assert(item_);
return (item_ == other.item_);
}
bool operator !=(const Iterator &other) {
assert(item_);
return (item_ != other.item_);
}
void move_before(Iterator &from) {
assert(item_);
assert(from);
assert(item_->prev_);
Item *before = item_->prev_;
Item *after = item_;
Item *item = from.item_;
// remove from old list
item->next_->prev_ = item->prev_;
item->prev_->next_ = item->next_;
// insert into this list
item->next_ = after;
item->prev_ = before;
before->next_ = item;
after->prev_ = item;
}
void insert_before(T *container) {
assert(item_);
assert(item_->prev_);
Item *before = item_->prev_;
Item *after = item_;
Item *item = &(container->*M);
// insert into this list
item->next_ = after;
item->prev_ = before;
before->next_ = item;
after->prev_ = item;
}
private:
Item *item_;
};
template <class T, Item T::*M>
class ConstIterator {
public:
ConstIterator() : item_(NULL) { }
ConstIterator(const T *container) : item_(&(container->*M)) { }
~ConstIterator() { }
operator bool() const {
assert(item_);
// not head and not tail
return ((item_->next_ != NULL) && (item_->prev_ != NULL));
}
const T & operator *() const {
assert(item_);
if ((item_->next_ == NULL) || (item_->prev_ == NULL)) {
// head or tail has no container
assert(false);
}
return *container_of<T, M>(item_);
}
const T & operator ->() const {
assert(item_);
if ((item_->next_ == NULL) || (item_->prev_ == NULL)) {
// head or tail has no container
assert(false);
}
return *container_of<T, M>(item_);
}
ConstIterator & operator ++() {
assert(item_);
assert(item_->next_);
item_ = item_->next_;
return *this;
}
ConstIterator & operator --() {
assert(item_);
assert(item_->prev_);
item_ = item_->prev_;
return *this;
}
bool operator ==(const ConstIterator &other) const {
assert(item_);
return (item_ == other.item_);
}
bool operator !=(const ConstIterator &other) {
assert(item_);
return (item_ != other.item_);
}
private:
const Item *item_;
};
template <class T, Item T::*M>
class Head {
public:
Head() : head_(&tail_, NULL), tail_(NULL, &head_) { }
~Head() { }
Iterator<T, M> head() {
return Iterator<T, M>(container_of<T, M>(&head_));
}
ConstIterator<T, M> head() const {
return ConstIterator<T, M>(container_of<T, M>(&head_));
}
Iterator<T, M> tail() {
return Iterator<T, M>(container_of<T, M>(&tail_));
}
ConstIterator<T, M> tail() const {
return ConstIterator<T, M>(container_of<T, M>(&tail_));
}
Iterator<T, M> first() {
return Iterator<T, M>(container_of<T, M>(head_.next_));
}
ConstIterator<T, M> first() const {
return ConstIterator<T, M>(container_of<T, M>(head_.next_));
}
Iterator<T, M> last() {
return Iterator<T, M>(container_of<T, M>(tail_.prev_));
}
ConstIterator<T, M> last() const {
return ConstIterator<T, M>(container_of<T, M>(tail_.prev_));
}
bool is_empty() const {
return (first() == tail());
}
private:
Head(const Head &) = delete;
Head & operator =(const Head &) = delete;
Item head_;
Item tail_;
};