meisel
meisel

Reputation: 2459

How can I create an iterator of a range of indexes in C++11?

I'm working with an API that takes a start and end iterator, and runs async work on the objects in that range. However, in one case I want to iterate over indexes of objects, not objects (from 0 to myVector.size() - 1). I could create a simple vector of those indexes and use its .begin() and .end() iterators, but that has unacceptable performance overhead.

What's the easiest way to create two iterators, where iterating from the first one to the second takes you from 0 to N?

Upvotes: 1

Views: 458

Answers (2)

eerorika
eerorika

Reputation: 238461

What's the easiest way to create two iterators, where iterating from the first one to the second takes you from 0 to N?

It seems that you're describing std::ranges::iota_view. Use begin and end to get the pair of iterators that you're looking for.

in C++11

Unfortunately, std::ranges::iota_view was introduced in C++20 and the original library ranges_v3 requires C++14.

But, there are other implementations of the same idea such boost::counting_iterator that work in C++11.

Or if you want to write the iterator from scratch, you can look at how the mentioned pre-existing implementations have been implemented. Writing custom iterators involves a ton of boilerplate, but this is among the simplest iterators that can be written.

Upvotes: 2

Miles Budnek
Miles Budnek

Reputation: 30694

If you have access to C++20, then you can use std::views::iota/std::ranges::iota_view to get a sequence of integers:

std::vector<SomeType> vec = ...
auto index_sequence = std::views::iota(std::size_t{0}, vec.size());
some_function_needing_iterators(std::begin(index_sequence), std::end(index_sequence));

Live Demo


Under previous standards, you can write your own numeric range iterator pretty easily; it just requires a bit of boilerplate:

template <typename T>
class NumericRangeIterator
{
public:
    using difference_type = std::ptrdiff_t;
    using value_type = T;
    using pointer = T const*;
    using reference = T const&;
    using iterator_category = std::bidirectional_iterator_tag;

    explicit NumericRangeIterator(T n) : n_{n} {}

    reference operator*() const
    {
        return n_;
    }

    pointer operator->() const
    {
        return &n_;
    }

    NumericRangeIterator& operator++()
    {
        ++n_;
        return *this;
    }

    NumericRangeIterator operator++(int)
    {
        return NumericRangeIterator{n_++};
    }

    NumericRangeIterator operator--()
    {
        --n_;
        return *this;
    }

    NumericRangeIterator operator--(int)
    {
        return NumericRangeIterator{n_--};
    }

    bool operator==(const NumericRangeIterator& other) const
    {
        return n_ == other.n_;
    }

    bool operator!=(const NumericRangeIterator& other) const
    {
        return !(*this == other);
    }

private:
    T n_;
};

int main() {
    std::vector<int> vec = ...;
    some_function_needing_iterators(
        NumericRangeIterator{size_t{0}},
        NumericRangeIterator{vec.size()}
    );
}

Live Demo

Upvotes: 3

Related Questions