为什么不擦除支持反向迭代器?

时间:2016-01-25 15:26:51

标签: c++ containers erase

我刚刚编写了以下代码,并且非常惊讶它没有编译:

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

如您所见,我想删除符合特定条件的最后一个元素(如果有)。

错误是

  

没有匹配的呼叫功能   的std ::双端队列::擦除(标准:: reverse_iterator的...

起初我不相信它是由反向迭代器引起的,但事实确实如此,因为用rbegin / rend替换begin / end

所以,2个问题:

  1. 为什么不支持此功能?它只是C ++委员会忘记包含在标准中的那些小事之一,还是缺少这种过载的理由?
  2. 做我想要的最优雅的方式是什么?我是否坚持按索引迭代?

2 个答案:

答案 0 :(得分:1)

我无法回答“为什么”这个问题,而是回答“如何” - 你应该在你的迭代器上调用base()。它将返回一个正确的前向迭代器。

在执行此操作时,请记住反向和正向迭代器之间的关系。起初可能会令人困惑,但实际上很简单。如果您的std::vector包含以下内容:

1, 2, 3, 4, 5

你有一个reverse_iterator rit,在解除引用时会给你3,然后*(rit.base)将等于4.要知道为什么,请记住在正常的迭代器中begin()是可以解除引用的,但end()不是。在反向迭代器中,属性必须相同 - rbegin()必须是不可引用的,但rend()不应该 - 也就是说,应该指向容器的开头。

根据定义,rend.base()begin()相同(因为rend可以构造为reverse_iterator(begin()),上述所有内容的唯一方法就是{{1} }会将一个右下角的元素返回到开头之外的那个元素 - rend.base()。很容易看出begin()的相同对称性也适用。

答案 1 :(得分:1)

我认为,在不需要“超载”的情况下,需要在整个标准库中添加的额外重载数量使其成为一项看起来似乎很麻烦的任务。

当然,“最优雅”的解决方法很难表达:

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

…但是有一个 ,并且反向迭代器使用的频率可能不足以保证所有地方都有重载而产生的所有额外噪声,这些重载无处不在,只包装了上面的代码行。

如果您发现自己经常使用它,则可以自己包装更通用的解决方案:

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

然后就是:

container.erase(AsForwardIterator(it));

坦率地说,这样做的简单性似乎不值得每个容器都包含所有这些重载。