我可以将逆向迭代器转换为向前迭代器吗?
我有一个名为Action
的类,它本质上是一个Move
对象的双层包装器。
因为我需要遍历向前和向后移动的双转移,所以我有一个前向迭代器和一个reverse_iterator作为类的成员variables。 之所以这样,是因为我必须知道,当我前进或后退的时候,我已经走过了一个人的“终点”。
这个类看起来像这样:
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; };
Advance
function如下:
void Action::Advance { if( bForward) currentfwd++; else currentbck++; }
我的问题是,我想能够检索一个迭代器到当前的Move
对象,而不需要查询我是前进还是后退。 这意味着一个函数返回一种types的迭代器,但我有两种types。
我应该忘记返回一个迭代器,而是返回一个Move
对象的const引用?
最好的祝愿,
BeeBand
这正是促使STL开始devise的问题。 有真正的原因:
- 不要将容器和迭代器一起存储
- 使用接受任意迭代器的algorithm
- 让algorithm一次性评估整个范围而不是单个项目
我怀疑你现在看到的是或多或less的真正问题的冰山一angular。 我的build议是后退一步,而不是问如何处理目前的devise细节,而是询问一个更为普遍的问题,即你想要完成什么,以及如何最好地完成最终结果。
对于那些主要关心标题中的问题的人来说,答案是非常合格的“是”。 特别是,reverse_iterator有一个base()
成员来做到这一点。 资格有些问题,但。
演示问题,考虑这样的代码:
#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"; }
在特定的机器上运行这个特定的时刻会产生以下输出:
4 0 4 -1879048016 1 -1879048016
总结:在使用rbegin()
函数转换为前向迭代器之前, 必须先添加一个迭代器才能获得有效的迭代器 – 但是对于rend()
我们不能在转换之前添加一个迭代器来获取有效的迭代器。
只要你使用X.rbegin()
和X.rend()
作为genericsalgorithm的参数,那很好,但是经验表明转换为迭代器通常会导致问题。
然而,最后,对于问题的主体(与标题相对),答案与上面相同:问题源于尝试创build一个将集合与几个迭代器结合到该集合中的对象。 解决这个问题,整个业务的前向和反向迭代器变得没有意义。
反向迭代器有一个成员base()
,它返回一个相应的forward迭代器。 请注意,这不是引用同一对象的迭代器 – 它实际上是指序列中的下一个对象。 这使得rbegin()
与end()
rbegin()
相对应,而rend()
与begin()
相对应。
所以如果你想返回一个迭代器,那么你会做类似的事情
std::deque<Move>::const_iterator Current() const { if (forward) return currentfwd; else return (currentbck+1).base(); }
我宁愿返回一个引用,然后封装类中的所有迭代细节。
由于std::deque
是一个随机访问容器 (与std::vector
相同),所以在两个遍历中使用单个整数索引进入deque要好得多。
在我看来,你在同一个class级实际上有两种不同的行为。
值得注意的是,你似乎只能以一个顺序遍历你的集合,否则如果你开始遍历,然后改变bforward
论点,你将最终有一个相当奇怪的情况。
就个人而言,我都是为了暴露这两个迭代器(即,前进begin, end, rbegin and rend
)。
你也可以返回一个简单的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); }
然后,你可以返回这个简单的对象:
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; };
或者,如果要在向前和向后遍历之间dynamicselect,则可以使Iterator成为纯虚拟接口,并具有向前和向后遍历。
但是真的,如果看起来你只使用一个,我真的不会看到存储BOTH前向和后向迭代器的要点:/
也许你应该重新考虑你select的容器。
通常你不需要使用反向迭代器来倒退,
currentfwd--
会倒退,尽pipe它可能无法正常工作(我假设你试过)与出列。
你真正应该做的就是把你的类作为dequeue的装饰器在这里build模,并实现你自己的Action迭代器。 无论如何,这将是我会做的。