C++ 中的自定义迭代器
我有一个 TContainer 类,它是几个指向 TItems 类的 stl 集合指针的集合。
我需要创建一个迭代器来遍历 TContainer 类中所有集合中的元素,抽象内部工作的客户端。
有什么好的方法可以做到这一点? 我是否应该创建一个扩展迭代器的类(如果是这样,我应该扩展哪个迭代器类),是否应该创建一个作为迭代器聚合的迭代器类?
我只需要一个 FORWARD_ONLY 迭代器。
即,如果这是我的容器:
typedef std::vector <TItem*> ItemVector;
class TContainer {
std::vector <ItemVector *> m_Items;
};
什么是一个好的迭代器来遍历 m_Items 成员变量的向量中包含的所有项目。
I have a class TContainer that is an aggregate of several stl collections pointers to TItems class.
I need to create an Iterator to traverse the elements in all the collections in my TContainer class abstracting the client of the inner workings.
What would be a good way to do this?. Should I crate a class that extends an iterator (if so, what iterator class should I extend), should I create an iterator class that is an aggregate of iterators?
I only need a FORWARD_ONLY iterator.
I.E, If this is my container:
typedef std::vector <TItem*> ItemVector;
class TContainer {
std::vector <ItemVector *> m_Items;
};
What would be a good Iterator to traverse all the items contained in the vectors of the m_Items member variable.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
当我做自己的迭代器时(不久前),我从 std::iterator 继承并将类型指定为第一个模板参数。 希望有帮助。
对于前向迭代器,在以下代码中使用forward_iterator_tag而不是input_iterator_tag。
这个类最初取自 istream_iterator 类(并根据我自己的使用进行了修改,因此它可能不再类似于 istram_iterator )。
检查有关迭代器标签的文档:
http://www.sgi.com/tech/stl/iterator_tags.html
刚刚重新阅读了有关迭代器的信息:
http://www.sgi.com/tech/stl/iterator_traits.html
这是旧的做事方式(iterator_tags),更现代的方法是设置 iterator_traits<> 让你的迭代器与STL完全兼容。
When I did my own iterator (a while ago now) I inherited from std::iterator and specified the type as the first template parameter. Hope that helps.
For forward iterators user forward_iterator_tag rather than input_iterator_tag in the following code.
This class was originally taken from istream_iterator class (and modified for my own use so it may not resemble the istram_iterator any more).
Check this documentation on iterator tags:
http://www.sgi.com/tech/stl/iterator_tags.html
Having just re-read the information on iterators:
http://www.sgi.com/tech/stl/iterator_traits.html
This is the old way of doing things (iterator_tags) the more modern approach is to set up iterator_traits<> for your iterator to make it fully compatible with the STL.
如果您有权访问 Boost,请使用
iterator_facade< /code>
是最强大的解决方案,而且使用起来非常简单。
If you have access to Boost, using
iterator_facade
is the most robust solution, and it's pretty simple to use.首先让我们概括一下:
现在迭代器:
此类假设外部迭代器包含指向内部范围的指针,这是您问题中的要求。 这反映在
update
成员中,即begin()
和end()
之前的箭头中。 如果您想在外部迭代器按值包含内部范围的更常见情况下使用此类,则可以将这些箭头替换为点。 请注意,顺便说一句,此类不知道内部范围包含指针的事实,只有该类的客户端需要知道这一点。如果我们使用 boost::iterator_facade ,代码可能会更短,但没有必要为如此简单的东西添加 boost 依赖项。 此外,唯一棘手的部分是相等和增量操作,无论如何我们都必须对它们进行编码。
我将以下样板成员保留为“供读者练习”:
另一个有趣的练习是将其转换为可与任意容器一起使用的模板。 代码基本相同,只是您必须在一些地方添加
typename
注释。使用示例:
打印:
First let's generalize a little bit:
Now the iterator:
This class assumes than the outer iterators contain pointers to the inner ranges, which was a requirement in your question. This is reflected in the
update
member, in the arrows beforebegin()
andend()
. You can replace these arrows with dots if you want to use this class in the more common situation where the outer iterator contains the inner ranges by value. Note BTW that this class is agnostic to the fact that the inner range contains pointers, only clients of the class will need to know that.The code could be shorter if we use
boost::iterator_facade
but it's not necessary to add a boost dependency for something so simple. Besides, the only tricky parts are the equality and increment operations, and we have to code those anyway.I've left the following boiler-plate members as "exercises for the reader":
Another interesting exercise is to turn this into a template which works with arbitrary containers. The code is basically the same except that you have to add
typename
annotations in a few places.Example of use:
Which prints:
迭代器只是一个支持特定接口的类。 至少,您将希望能够:
一旦您拥有一个可以为您明智地执行此操作的类集合,您将需要修改集合以具有返回迭代器的函数。 至少,您需要
An iterator is just a class that supports a certain interface. At minimum, you will want to be able to:
Once you have a class that can do that sensibly for your collection, you will need to modify the collection to have functions that return iterators. At minimum you will want
检查视图模板库。
特别是检查
Check the Views Template Library.
Especially check
这是我能够生成的最简单的代码(对于自定义迭代器)。 请注意,我才刚刚开始探索这个领域。 这会调用内置的
upper_bound
函数对整数函数执行二分查找,例如x^2
。输出如下所示:
This is the simplest code I was able to produce (for custom iterators). Note that I'm only beginning to explore this area. This calls built-in
upper_bound
function to perform binary search on an integer function,x^2
as an example.And this is how the output looks like:
添加到建议使用 Boost.iterator 的 iterator_facade 来实现自定义迭代器的答案中,我编写了一个独立的、仅包含头文件的库,它模仿了 Boost.iterator 提供的(重要)部分。 好处是没有 Boost 依赖项(也没有除 C++17 之外的任何其他依赖项)。
我的库的一个显着特征是,通过使用它,您的迭代器将始终遵循迭代器接口的标准要求仅此而已。 这确保下游用户不会依赖当前迭代器实现的实现细节(将来可能会被删除/更改)。 这应该有助于提高可移植性和可维护性。
您可以在 https://github.com/Krzmbrzl/iterators 找到该库。
以下是如何使用此库创建自定义迭代器的示例:
Adding to the answer that suggests using Boost.iterator's
iterator_facade
in order to implement custom iterators, I have written a standalone, header-only library that mimics (the important) parts of what Boost.iterator provides. The benefit being that there is no Boost dependency (nor any other dependency except C++17).A distinct feature of my library is that by using it, your iterators will always follow the standard's requirement on the iterator's interface and nothing more. This makes sure that downstream users won't depend on an implementation detail of the current iterator implementation (that might be removed/changed in the future). This should help to increase portability and maintainability.
You can find the library at https://github.com/Krzmbrzl/iterators.
Here's an example of how to create a custom iterator with this library: