自定义容器基于范围的迭代
Custom container range-based iteration
我有一个自定义容器,我想在基于范围的 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;
};
我想迭代 mItems
向量,但只是 return mItem
成员而不是整个 Item
结构。有什么 easy/elegant 方法可以做到这一点吗?
如果你想让基于范围的 for 为你的容器工作,你必须提供 begin 和 end 函数 return 前向迭代器。
typedef std::vector<Item>::iterator iterator;
typedef std::vector<Item>::const_iterator const_iterator;
iterator begin()
{
return mItems.begin();
}
const_iterator begin() const;
{
return mItems.begin();
}
//also add end functions, and viola.
这将 return 整个项目结构。如果您只需要 return mItem,则必须编写自己的迭代器适配器并使用它代替向量。
你必须提供一个 begin
和 end
函数,它们都返回一个相应的迭代器,它本身实现了运算符 ++
、!=
和 *
. begin
和 end
函数可以是独立的或作为成员。
从实现具有您想要的行为的迭代器开始。您可以将其实现为 std::vector::iterator
的包装器,以节省大部分 "core" 工作。
以下是未经测试的代码
基本上,在 class 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() ); }
如果你想在你的 IDMap 上支持多种 "special iteration",比如在索引上,或者在 "whole" 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());
}
};
然后,你可以这样写:
IDMap<int> map = ...;
for (int i : map.items()) {
...
}
我有一个自定义容器,我想在基于范围的 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;
};
我想迭代 mItems
向量,但只是 return mItem
成员而不是整个 Item
结构。有什么 easy/elegant 方法可以做到这一点吗?
如果你想让基于范围的 for 为你的容器工作,你必须提供 begin 和 end 函数 return 前向迭代器。
typedef std::vector<Item>::iterator iterator;
typedef std::vector<Item>::const_iterator const_iterator;
iterator begin()
{
return mItems.begin();
}
const_iterator begin() const;
{
return mItems.begin();
}
//also add end functions, and viola.
这将 return 整个项目结构。如果您只需要 return mItem,则必须编写自己的迭代器适配器并使用它代替向量。
你必须提供一个 begin
和 end
函数,它们都返回一个相应的迭代器,它本身实现了运算符 ++
、!=
和 *
. begin
和 end
函数可以是独立的或作为成员。
从实现具有您想要的行为的迭代器开始。您可以将其实现为 std::vector::iterator
的包装器,以节省大部分 "core" 工作。
以下是未经测试的代码
基本上,在 class 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() ); }
如果你想在你的 IDMap 上支持多种 "special iteration",比如在索引上,或者在 "whole" 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());
}
};
然后,你可以这样写:
IDMap<int> map = ...;
for (int i : map.items()) {
...
}