'Incrementing iterator from end to begin

I want to iterate over a vector and when reaching the end it should loop back to the front.

This is a small example which does not compile

#include <vector>

std::vector<int>::iterator Next(const std::vector<int>& vec, 
    const std::vector<int>::iterator it) 
{
    auto itNext = it+1;
    if (itNext == vec.end())
        itNext = vec.begin(); // breaks 
    return itNext;
}

int main()
{
    std::vector x{0, 2, 3, 4};
    auto it = x.begin()+1;        
    return *Next(x,it);
}

and here a godbolt link.

The issue arises because of no available conversion between vector::const_iterator (result of begin()) and vector::iterator. How can one fix this issue?



Solution 1:[1]

You cannot convert a const_iterator to an iterator because this would break const-correctness.

You basically have two options. When it is ok to return a const_iterator then return a const_iterator:

#include <vector>

std::vector<int>::const_iterator Next(const std::vector<int>& vec, 
    std::vector<int>::const_iterator it) 
{
    auto itNext = it+1;
    if (itNext == vec.end())
        itNext = vec.begin();
    return itNext;
}

int main()
{
    std::vector x{0, 2, 3, 4};
    auto it = x.begin()+1;        
    return *Next(x,it);
}

You can only get a const_iterator from a const std::vector&. Hence if you want to return an iterator the vector has to be passes as non-const reference:

#include <vector>

std::vector<int>::iterator Next(std::vector<int>& vec, 
    std::vector<int>::iterator it) 
{
    auto itNext = it+1;
    if (itNext == vec.end())
        itNext = vec.begin(); 
    return itNext;
}

int main()
{
    std::vector x{0, 2, 3, 4};
    auto it = x.begin()+1;        
    return *Next(x,it);
}

To have both in one I would pass iterators and make the function a template, so it can be used with iterator or const_iterator. The function might grant you non-const access to the vectors elements, but for the function itself it doesn't matter that much if the iterators are const or not.

#include <vector>


template <typename IT>
IT Next(IT it,IT begin,IT end) {
    auto itNext = it+1;
    return (itNext == end) ? begin : itNext;
}

int main()
{
    std::vector x{0, 2, 3, 4};
    auto it = x.begin()+1;        
    auto it2 = Next(it,x.begin(),x.end());
    *it2 = 42;
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1