1

我目前正在使用一个第三方库,其中包含一个仅提供索引查找的类,即operator[].

我想对这个类的内容做一个基于范围的 for 循环。但是,由于从未编写过迭代器或迭代器适配器,我很迷茫。似乎编写迭代器并不是一项简单的任务。

我想要的用法是:

for(auto element : container)
{
    ...
}

而不必写:

for(int i = 0; i < container.size(); ++i)
{
    auto element = container[i];
    ...
}

如何做到这一点?Boost 是否提供此功能?

4

2 回答 2

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_;
};

继承 fromstd::iterator方便地声明适当的 typedef 以用于std::iterator_traits.

然后,您将定义beginend如下:

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 此处

vector_view可以在Coliruideone.com上找到上述的随机访问迭代器实现,以及一个简单类的使用演示。

于 2014-04-02T17:47:18.050 回答
1

您可以执行以下操作:

1)定义您自己的迭代器,其中包含容器It的 ref和 index 。当迭代器被取消引用时,它通过引用返回。您可以自己编写它,也可以使用 boost 寻求帮助,它有一个迭代器库,可以轻松定义您自己的迭代器。构造函数应该接受 a和 a 。如果此概念适用,您也可以制作。refcontaineriref[i]container&size_tconst_iterator

2) 当operator++在一个迭代器上调用时,它只是++i在内部成员上执行。operator==并且operator!=应该简单地比较iassert为了安全起见,您可以确保两个迭代器是一致的,这意味着它们ref的 s 指向同一个对象。

3)将beginand添加end到您的容器类中,或者,如果这不可能,请定义一个全局beginend接受您的container& c. begin应该简单地返回It(c, 0)end应该返回It(c, c.size())

复制迭代器可能会出现问题,因为它们包含引用和其他一些小细节,但我希望总体思路清晰正确。

于 2014-04-02T16:21:32.103 回答