[英]Can I convert a reverse iterator to a forward iterator?
我有一個名為Action
的類,它本質上是一個圍繞Move
對象雙端隊列的包裝器。
因為我需要向前和向后遍歷Moves
的雙端隊列,所以我有一個前向迭代器和一個reverse_iterator作為類的成員變量。 這樣做的原因是因為我需要知道什么時候我已經超過了雙端隊列的“結束”,無論是前進還是后退。
這個類看起來像這樣:
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
功能如下:
void Action::Advance
{
if( bForward)
currentfwd++;
else
currentbck++;
}
我的問題是,我希望能夠檢索到當前Move
對象的迭代器,而無需查詢我是向前還是向后。 這意味着一個函數返回一種類型的迭代器,但我有兩種類型。
我應該忘記返回迭代器,而是返回對Move
對象的 const 引用嗎?
反向迭代器有一個成員base()
,它返回一個相應的正向迭代器。 請注意,這不是引用同一對象的迭代器 - 它實際上是指序列中的下一個對象。 這是因為rbegin()
對應於end()
並且rend()
對應於begin()
。
所以如果你想返回一個迭代器,那么你會做類似的事情
std::deque<Move>::const_iterator Current() const
{
if (forward)
return currentfwd;
else
return (currentbck+1).base();
}
不過,我更願意返回一個引用,並將所有迭代細節封裝在類中。
這正是促使 STL 設計開始的那種問題。 有以下真實原因:
我懷疑你現在看到的或多或少是真正問題的冰山一角。 我的建議是退后一步,不要問如何處理目前的設計細節,而是問一個更一般的問題,關於你想要完成什么,以及如何最好地完成它最終結果。
對於那些主要關心標題中問題的人來說,答案是非常合格的“是”。 特別是,一個 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()
作為泛型算法的參數,那很好——但經驗表明,轉換為前向迭代器通常會導致問題。
然而,最后,對於問題的主體(而不是標題),答案幾乎與上面給出的一樣:問題源於試圖創建一個對象,該對象將集合與幾個迭代器組合到該集合中. 解決這個問題,整個帶有正向和反向迭代器的業務就變得沒有意義了。
由於std::deque
是一個隨機訪問容器(與std::vector
相同),因此您最好在兩次遍歷中使用單個整數索引進入雙端隊列。
在我看來,您實際上在同一個班級中有兩種不同的行為。
值得注意的是,您似乎只能以一種順序遍歷您的集合,否則如果您要開始遍歷然后更改bforward
參數,您最終會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;
};
或者,如果您想在向前和向后遍歷之間動態選擇,您可以使 Iterator 成為一個純虛擬接口並同時具有向前和向后遍歷。
但實際上,如果看起來你只會使用一個,我真的不明白同時存儲向前和向后迭代器的意義:/
也許您應該重新考慮對容器的選擇。
通常你不需要使用反向迭代器來倒退,
currentfwd--
會倒退,盡管它可能無法與出隊一起工作(我假設您嘗試過)。
您真正應該做的是將您的類建模為出隊的裝飾器並實現您自己的 Action 迭代器。 無論如何,這就是我要做的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.