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

C++ 我可以将反向迭代器转换为正向迭代器吗?,c++,iterator,C++,Iterator,我有一个名为Action的类,它本质上是一个围绕Move对象的包装器 因为我需要向前和向后遍历移动的deque,所以我有一个向前迭代器和一个反向迭代器作为类的成员变量。这样做的原因是因为我需要知道我什么时候已经过了德克的“终点”,无论是向前还是向后 该类如下所示: class Action { public: SetMoves(std::deque<Move> & dmoves) { _moves = dmoves; } void Advance();

我有一个名为
Action
的类,它本质上是一个围绕
Move
对象的包装器

因为我需要向前和向后遍历
移动的deque,所以我有一个向前迭代器和一个反向迭代器作为类的成员变量。这样做的原因是因为我需要知道我什么时候已经过了德克的“终点”,无论是向前还是向后

该类如下所示:

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;
};
#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";
}
我的问题是,我希望能够检索到当前
Move
对象的迭代器,而不需要查询是向前还是向后。这意味着一个函数返回一种类型的迭代器,但我有两种类型


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

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

通常,您不需要使用反向迭代器进行反向运算

currentfwd--
将倒退,尽管它可能不适用于(我假设您尝试过)出列


您真正应该做的是在这里将您的类建模为出列的装饰器,并实现您自己的动作迭代器。无论如何,我都会这样做。

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

因此,如果您想返回一个迭代器,那么您可以执行以下操作

std::deque<Move>::const_iterator Current() const
{
    if (forward)
        return currentfwd;
    else
        return (currentbck+1).base();
}
std::deque::const\u迭代器Current()const
{
如果(转发)
返回电流fwd;
其他的
返回值(currentbck+1).base();
}

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

因为
是一个(与
std::vector
相同)对于两次遍历,最好在deque中使用一个整数索引。

在我看来,在同一个类中实际上有两种不同的行为

值得注意的是,您似乎只能按一个顺序遍历集合,否则,如果您开始遍历,然后更改
b forward
参数,您将遇到非常奇怪的情况

就个人而言,我完全支持公开这两个迭代器(即,forward
begin、end、rbegin和rend

您还可以返回一个简单的迭代器对象:

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); }
模板
类迭代器
{
公众:
typedef typename T::reference_type reference_type;
迭代器(T it,T end):m_it(it),m_end(end){}
运算符bool()常量{返回m_it!=m_end;}
引用类型运算符*()常量{return*m_it;}
迭代器和运算符+++(){++m_it;返回*this;}
私人:
T m_it;
T m_end;
};
模板
迭代器使_迭代器(T it,T end){返回迭代器(it,end);}
然后,您只需返回以下简单对象:

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;
};
集体诉讼
{
公众:
动作(std::deque const&d):m_deque(d){}//const&please
typedef迭代器forward\u Iterator\u type;
typedef迭代器backward_Iterator_type;
前向迭代器类型前向迭代器()
{
返回make_迭代器(m_deque.begin(),m_deque.end());
}
反向迭代器类型反向迭代器()
{
返回make_迭代器(m_deque.rbegin(),m_deque.rend());
}
私人:
std::deque m_deque;
};
或者,如果您想在正向和反向遍历之间动态选择,您可以将迭代器设置为纯虚拟接口,同时具有正向和反向遍历

但实际上,如果看起来您只会使用一个,那么我真的看不到同时存储正向和反向迭代器的意义:/

这正是促使STL设计开始的那种问题。有真正的原因:
  • 不使用接受任意迭代器的算法将迭代器与容器一起存储
  • 让算法一次计算整个范围,而不是单个项

    我怀疑你现在看到的或多或少是真正问题的冰山一角。我的建议是退后一步,而不是询问如何处理当前设计的细节,而是询问一个更一般的问题,即您试图实现什么,以及如何最好地实现最终结果

    对于那些主要关心标题中问题的人来说,答案是一个严格限定的“是”。特别是,反向迭代器有一个
    base()
    成员来执行此操作。不过,这些条件有些问题

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

    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;
    };
    
    #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";
    }
    
    摘要:对于
    rbegin()
    我们必须在转换为正向迭代器之前添加一个迭代器,才能获得有效的迭代器——但是对于
    rend()
    我们不能在转换为有效迭代器之前添加一个迭代器

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


    然而,最后,对于问题的主体(与标题相反),答案与上面给出的基本相同:问题源于尝试创建一个对象,该对象将集合与两个迭代器组合到该集合中。如果解决了这个问题,那么使用正向和反向迭代器的整个业务将变得毫无意义。

    谢谢Charles。返回的问题是Finished()函数中的问题-当我在第一个元素前一个元素(即,已经超过了“rend()”)时,我需要知道。谢谢-我一直在应用程序的其余部分使用deque,正是出于这个原因。我不知道为什么我对迭代器有一种隧道式的看法:-)这就是w