C++ 我可以将反向迭代器转换为正向迭代器吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2037867/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:55:15  来源:igfitidea点击:

Can I convert a reverse iterator to a forward iterator?

c++iterator

提问by BeeBand

I have a class called Action, which is essentially a wrapper around a deque of Moveobjects.

我有一个名为 的类Action,它本质上是一个Move对象双端队列的包装器。

Because I need to traverse the deque of Movesboth forward and backwards, I have a forward iterator and a reverse_iterator as member variables of the class. The reason for this is becuase I need to know when I have gone one past the "end" of the deque, both when I am going forwards or backwards.

因为我需要遍历Movesforward和backward的双端队列,所以我有一个前向迭代器和一个reverse_iterator作为类的成员变量。这样做的原因是因为我需要知道什么时候我已经超过了双端队列的“结束”,无论是前进还是后退。

The class looks like this:

这个类看起来像这样:

class Action
{
public:
    SetMoves(std::deque<Move> & dmoves) { _moves = dmoves; }
    void Advance();
    bool Finished() 
    {
        if( bForward )
            return (currentfwd==_moves.end());
        else
            return (currentbck==_moves.rend());
    }
private:
    std::deque<Move> _moves;
    std::deque<Move>::const_iterator currentfwd;
    std::deque<Move>::const_reverse_iterator currentbck;
    bool bForward;
};

The Advancefunction is as follows:

Advance功能如下:

void Action::Advance
{
    if( bForward)
        currentfwd++;
    else
        currentbck++;
}

My problem is, I want to be able to retrieve an iterator to the current Moveobject, without needing to query whether I am going forwards or backwards. This means one function returning one type of iterator, but I have two types.

我的问题是,我希望能够检索到当前Move对象的迭代器,而无需查询我是前进还是后退。这意味着一个函数返回一种类型的迭代器,但我有两种类型。

Should I forget returning an iterator, and return a const reference to a Moveobject instead?

我应该忘记返回迭代器,Move而是返回对对象的 const 引用 吗?

best wishes,

最好的祝愿,

BeeBand

手环

采纳答案by Jerry Coffin

This is exactlythe sort of problem that prompted the design of STL to start with. There are real reasons for:

正是促使 STL 设计开始的那种问题。有以下真实原因:

  1. Not storing iterators along with containers
  2. Using algorithms that accept arbitrary iterators
  3. Having algorithms evaluate an entire range instead of a single item at a time
  1. 不将迭代器与容器一起存储
  2. 使用接受任意迭代器的算法
  3. 让算法一次评估整个范围而不是单个项目

I suspect what you're seeing right now is more or less the tip of the iceberg of the real problems. My advice would be to take a step back, and instead of asking about how to deal with the details of the design as it currently stands, ask a somewhat more general question about what you're trying to accomplish, and how best to accomplish that end result.

我怀疑你现在看到的或多或少是真正问题的冰山一角。我的建议是退后一步,不要问如何处理目前的设计细节,而是问一个更一般的问题,关于你想要完成什么,以及如何最好地完成它最终结果。

For those who care primarily about the question in the title, the answer is a heavily qualified "yes". In particular, a reverse_iterator has a base()member to do that. The qualifications are somewhat problematic though.

对于那些主要关心标题中问题的人来说,答案是非常合格的“是”。特别是,一个 reverse_iterator 有一个base()成员来做到这一点。不过资质有点问题。

The demonstrate the problem, consider code like this:

演示问题,考虑这样的代码:

#include <iostream>
#include <vector>
#include <iterator>

int main() { 
    int i[] = { 1, 2, 3, 4};
    std::vector<int> numbers(i, i+4);

    std::cout << *numbers.rbegin() << "\n";
    std::cout << *numbers.rbegin().base() << "\n";
    std::cout << *(numbers.rbegin()+1).base() << "\n";

    std::cout << *numbers.rend() << "\n";
    std::cout << *numbers.rend().base() << "\n";
    std::cout << *(numbers.rend()+1).base() << "\n";
}

Running this at this particular moment on my particular machine produces the following output:

在这个特定时刻在我的特定机器上运行它会产生以下输出:

4
0
4
-1879048016
1
-1879048016

Summary: with rbegin()we mustadd one before converting to a forward iterator to get an iterator that's valid -- but with rend()we must notadd one before converting to get a valid iterator.

总结:rbegin()我们必须在转换为前向迭代器之前添加一个来获得一个有效的迭代器——但是rend()我们不能在转换为一个有效的迭代器之前添加一个。

As long as you're using X.rbegin()and X.rend()as the parameters to a generic algorithm, that's fine--but experience indicates that converting to forward iterators often leads to problems.

只要您使用X.rbegin()X.rend()作为通用算法的参数,那很好——但经验表明,转换为前向迭代器通常会导致问题。

In the end, however, for the body of the question (as opposed to the title), the answer is pretty much as given above: the problem stems from trying to create an object that combines the collection with a couple of iterators into that collection. Fix that problem, and the whole business with forward and reverse iterators becomes moot.

然而,最后,对于问题的主体(而不是标题),答案几乎与上面给出的一样:问题源于试图创建一个对象,该对象将集合与几个迭代器组合到该集合中. 解决这个问题,整个带有正向和反向迭代器的业务就变得没有意义了。

回答by Mike Seymour

Reverse iterators have a member base()which returns a corresponding forward iterator. Beware that this isn'tan iterator that refers to the same object - it actually refers to the next object in the sequence. This is so that rbegin()corresponds with end()and rend()corresponds with begin().

反向迭代器有一个成员base(),它返回相应的正向迭代器。请注意,这不是引用同一对象的迭代器 - 它实际上是指序列中的下一个对象。这就是rbegin()对应于end()并且rend()对应于begin()

So if you want to return an iterator, then you would do something like

所以如果你想返回一个迭代器,那么你会做类似的事情

std::deque<Move>::const_iterator Current() const
{
    if (forward)
        return currentfwd;
    else
        return (currentbck+1).base();
}

I would prefer to return a reference, though, and encapsulate all the iteration details inside the class.

不过,我更愿意返回一个引用,并将所有迭代细节封装在类中。

回答by Nikolai Fetissov

Since std::dequeis a random access container(same as std::vector) you are much better off using a single integer index into the deque for both traversals.

由于std::deque随机访问容器(与 相同std::vector),因此最好在双端队列中使用单个整数索引进行两次遍历。

回答by Matthieu M.

It seems to me that you actually have two different behavior in the same class.

在我看来,您实际上在同一个班级中有两种不同的行为。

Notably, it seems that you can only traverse your collection in one order, otherwise if you were to begin the traversal and then change the bforwardargument you would end up with quite a strange situation.

值得注意的是,您似乎只能以一种顺序遍历您的集合,否则如果您要开始遍历然后更改bforward参数,您最终会遇到非常奇怪的情况。

Personally, I am all for exposing both iterators (ie, forward begin, end, rbegin and rend).

就个人而言,我完全赞成公开两个迭代器(即 forward begin, end, rbegin and rend)。

You could also return a simple Iterator object:

您还可以返回一个简单的 Iterator 对象:

template <class T>
class Iterator
{
public:
  typedef typename T::reference_type reference_type;

  Iterator(T it, T end) : m_it(it), m_end(end) {}

  operator bool() const { return m_it != m_end; }

  reference_type operator*() const { return *m_it; }

  Iterator& operator++() { ++m_it; return *this; }

private:
  T m_it;
  T m_end;
};

template <class T>
Iterator<T> make_iterator(T it, T end) { return Iterator<T>(it,end); }

Then, you can just return this simple object:

然后,您可以返回这个简单的对象:

class Action
{
public:
  Action(std::deque<Move> const& d): m_deque(d) {} // const& please

  typedef Iterator< std::deque<Move>::iterator > forward_iterator_type;
  typedef Iterator< std::deque<Move>::reverse_iterator > backward_iterator_type;

  forward_iterator_type forward_iterator()
  {
    return make_iterator(m_deque.begin(), m_deque.end());
  }

  backward_iterator_type backward_iterator()
  {
    return make_iterator(m_deque.rbegin(), m_deque.rend());
  }


private:
  std::deque<Move> m_deque;
};

Or if you want to choose dynamically between forward and backward traversal, you could make Iterator a pure virtual interface and having both forward and backward traversal.

或者,如果您想在向前和向后遍历之间动态选择,您可以使 Iterator 成为一个纯虚拟接口并同时具有向前和向后遍历。

But really, I don't really see the point of storing BOTH forward and backward iterator if it appears that you will only use one :/

但实际上,如果看起来你只会使用一个,我真的不明白同时存储向前和向后迭代器的意义:/

回答by Charles

Maybe you should rethink your choice of container.

也许您应该重新考虑对容器的选择。

Usually you do not need to use reverse iterators to go backward,

通常你不需要使用反向迭代器来倒退,

currentfwd--

will go backwards, all though it might not work (which i assume you tried) with dequeue.

会倒退,尽管它可能无法与出队一起工作(我假设您尝试过)。

What you should really do is model your class here as a decorator of dequeue and implement your own Action iterators. That would be what I would do anyway.

您真正应该做的是将您的类建模为出队的装饰器并实现您自己的 Action 迭代器。无论如何,这就是我要做的。