我目前正在使用第三方库,其中包含仅提供索引查找的类,即operator[]
。
我想在这个课程的内容上做一个基于范围的for循环。但是,从未编写过迭代器或迭代器适配器,我很遗憾。似乎编写迭代器并不是一项简单的任务。
我想要的用法是:
for(auto element : container)
{
...
}
而不是写:
for(int i = 0; i < container.size(); ++i)
{
auto element = container[i];
...
}
如何实现这一目标? Boost是否提供此功能?
答案 0 :(得分:3)
编写迭代器实际上是一项相当简单的任务,但它变得非常繁琐。由于您的容器支持整数索引,我假设它的迭代器将落入随机访问迭代器类别(如果它们存在)。这需要很多样板!
但是,为了支持基于范围的for循环,您只需要一个前向迭代器。我们将为实现前向迭代器要求的容器编写一个简单的包装器,然后编写两个函数Iterator begin(Container&)
和Iterator end(Container&)
,使容器能够在基于范围的for循环中使用。
此Iterator
将包含对容器的引用,容器的大小以及该容器中的当前索引:
template<template<typename> class C, typename T>
class indexer : public std::iterator<std::forward_iterator, T>
{
public:
indexer(C<T>& c, std::size_t i, std::size_t end)
: c_(std::addressof(c)), i_(i), end_(end) {}
T& operator*() const {
return c_[i_];
}
indexer<C, T>& operator++() {
++i_;
return *this;
}
indexer<C, T> operator++(int) {
auto&& tmp = *this;
operator++();
return tmp;
}
bool operator==(indexer<C, T> const& other) const {
return i_ == other.i_;
}
bool operator!=(indexer<C, T> const& other) const {
return !(*this == other);
}
private:
C<T>* c_;
std::size_t i_, end_;
};
从std::iterator
继承可以方便地声明相应的typedef,以便与std::iterator_traits
一起使用。
然后,您可以按如下方式定义begin
和end
:
template<typename T>
indexer<Container, T> begin(Container<T>& c) {
return indexer<Container, T>(c, 0, c.size());
}
template<typename T>
indexer<Container, T> end(Container<T>& c) {
auto size = c.size();
return indexer<Container, T>(c, size, size);
}
根据您的示例中的Container
类型切换container
,然后,您所需的使用情况有效!
所有各种迭代器的要求和行为可以在标准的第24.2.2节的表格中找到,这些表格在cppreference.com here处镜像。
上面的随机访问迭代器实现,以及简单vector_view
类的使用演示,可以在Coliru或ideone.com上找到。
答案 1 :(得分:1)
您可以执行以下操作:
1)定义您自己的迭代器It
,其内部包含对容器ref
的引用container
和索引i
。取消引用迭代器后,它将通过引用返回ref[i]
。你可以自己编写它,或者你可以使用boost来获得帮助,它有一个迭代器库来轻松定义你自己的迭代器。构造函数应该接受container&
和size_t
。如果这个概念适用,你也可以const_iterator
。
2)当在一个迭代器上调用operator++
时,它只在内部成员上执行++i
。 operator==
和operator!=
应该只是比较i
。出于安全考虑,您可以assert
两个迭代器是连贯的,这意味着它们ref
指向同一个对象。
3)将begin
和end
添加到您的容器类中,或者,如果无法这样做,请定义接受begin
的全局end
和container& c
}。 begin
应该只返回It(c, 0)
。 end
应该返回It(c, c.size())
。
复制迭代器可能会出现问题,因为它们包含引用和其他一些细节,但我希望整体思路清晰正确。