Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't erase support reverse iterators?

I've just written the following code, and was very surprised it doesn't compile:

std::deque<int> container;
// filling the container...
for (auto it = container.rbegin(); it != container.rend(); ++it)
    if (*it == 5)
    {
        container.erase(it);
        break;
    }

As you can see, I want to delete the last element matching a certain criteria, if any.

The error is

no matching function for call to std::deque::erase(std::reverse_iterator...

At first I didn't believe it was caused by the reverse iterator, but that is indeed the case since replacing rbegin/rend with begin/end solves it.

So, 2 questions:

  1. Why isn't this supported? Is it merely one of those little things the C++ committee forgot to include in the standard, or is there a justification for this overload missing?
  2. What is the most elegant way to do what I want? Am I stuck with iterating by index?
like image 878
Violet Giraffe Avatar asked Jan 25 '16 15:01

Violet Giraffe


People also ask

Is iterator valid after erase?

All of the iterators, and references, which are after the deletion point, are invalidated. Same as like insert or erase. All iterators and the references are invalidated if the inserted item is not inserted at the end of the deque.

How does a reverse iterator work?

C++ Iterators Reverse IteratorsA reverse iterator is made from a bidirectional, or random access iterator which it keeps as a member which can be accessed through base() . To iterate backwards use rbegin() and rend() as the iterators for the end of the collection, and the start of the collection respectively.


1 Answers

I figure that the quantity of additional overloads that would need to be added throughout the standard library make this an unseemly task, when there is no "need" for it.

Sure, the "most elegant" workaround is hardly expressive:

container.erase((it+1).base());

…but there is one, and reverse iterators are likely not used often enough to warrant all the extra noise that would be caused by having overloads everywhere that do nothing but wrap the above line of code.

If you find yourself using it a lot, you can wrap the more general solution yourself:

template <typename ReverseIterator>
auto AsForwardIterator(ReverseIterator rit)
{
    std::advance(rit, 1);
    return rit.base();
}

Then it's just:

container.erase(AsForwardIterator(it));

And, quite frankly, the simplicity of this seems worth not having all those overloads in every container.

like image 179
Asteroids With Wings Avatar answered Oct 14 '22 07:10

Asteroids With Wings