自定义容器基于范围的迭代

Kai*_*aan 6 c++ containers

我有一个自定义容器,我想在基于范围的for循环中使用它.容器有点基于向量,如下所示:

template<typename T>
class IDMap
{
private:
    struct Item {
        uint16_t mVersion;
        T mItem;

        template <typename... Arguments>
        Item(uint16_t version, Arguments&&... args) : mVersion(version), mItem(args...)
        {
        }
    };


public:
    typedef uint32_t ItemID;

    template <typename... Arguments>
    ItemID AddItem(Arguments&&... args);

    void MarkAsFree(const ItemID id);

    T& GetItem(const ItemID id);

    T* TryGetItem(const ItemID id);

    void Clear();


private:
    std::vector<Item> mItems;
    std::vector<uint16_t> mFreeIndices;
};
Run Code Online (Sandbox Code Playgroud)

我想迭代mItems向量,但只返回mItem成员而不是整个Item结构.有没有简单/优雅的方法来做到这一点?

lee*_*mes 6

你必须提供一个beginend函数,它们都返回一个相应的迭代器,它本身实现了运算符++,!=以及*.这些beginend功能可以是独立的或作为成员.

首先实现具有所需行为的迭代器.您可以将其实现为包装,std::vector::iterator以保存大部分"核心"工作.

以下是未经测试的代码

基本上,在类IDMap中,添加:

class ItemIterator {
    // based on vector iterator
    std::vector<Item>::iterator i;
public:
    ItemIterator(std::vector<Item>::iterator i) : i(i) {}

    // incrementing
    ItemIterator & operator ++() { ++i; return *this; }
    ItemIterator operator ++(int) { const_iterator old(*this); ++(*this); return old; }

    // comparison
    bool operator!=(const ItemIterator &o) const { return i != o.i; }

    // dereferencing
    const T & operator*() const { return i->mItem; }
};

using iterator = ItemIterator;
using value_type = T;

ItemIterator begin() const { return ItemIterator(mItems.begin()); }
ItemIterator end()   const { return ItemIterator(mItems.end()  ); }
Run Code Online (Sandbox Code Playgroud)

如果你想在你的IDMap上支持多种"特殊迭代",例如在索引上,或者在整个"整体"上Item,你应该将所有内容包装在另一个适配器中.然后可以使用成员方法访问此适配器,例如.items().

简要示例:

class IDMap {
    // (your code)

public:
    struct ItemsAdaptor {
        // (insert above iterator definition + usings)

        ItemsAdaptor(std::vector<Item>::iterator b,
                     std::vector<Item>::iterator e)
            : b{b}, e{e}
        {}

        ItemIterator begin() const { return b; }
        ItemIterator end()   const { return e; }

    private:
        ItemIterator b, e;
    };

    ItemsAdaptor items() const {
        return ItemsAdaptor(mItems.begin(), mItems.end());
    }
};
Run Code Online (Sandbox Code Playgroud)

然后,你可以写:

IDMap<int> map = ...;

for (int i : map.items()) {
    ...
}
Run Code Online (Sandbox Code Playgroud)