解決策を見つけました。100%完璧ではありませんが、ほぼ完璧です。
アイデアは、3つのクラスを持つことです:
class Item;
template <class T, Item T::*M> class Iterator;
template <class T, Item T::*M> class Head;
Item クラスには、メモリ内の実際のリストを形成する次/前のリンクが含まれています。これには、コンテナーの種類とコンテナー内のリストの位置は含まれず、(それ自体では) 安全ではありません。しかし、Item にはリストを変更するメソッドがありません。すべての変更は Iterator を通じて行われます。Head を使用して Iterator を取得し、それを使用して next/prev ポインターを初期化することもできます。
Iterator クラスはコンテナー T から構築でき、演算子 ++、--、==、および != を持ち、コンテナーを現在の位置に挿入したり、コンテナーを別のイテレーターの背後にある独自のリストに移動したりできます。Iterator には、現在のコンテナーを返す演算子 * と、リストの最後に到達したかどうかを示す演算子 bool もあります。
Head クラスには、それぞれ prev==NULL と next==NULL を持つ特別な head と tail Item が含まれています。それらはコンテナ T のインスタンス内になく、リストの開始と終了をマークするため、特別です。終了マーカーを保持する以外に、Head は、先頭、末尾、最初と最後の要素を指す Iterator を作成するメソッドを提供します。これにより、リストを繰り返したり、最初または最後に挿入したりできます。
Iterator に似ていますが、const アクセス用の 4 番目のクラス ConstIterator があります。
注: これは最小限のテストのみです。残りのエラーは、読者が修正するために残されています。
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_;
};