2010-12-10 18 views
11

なぜ、コンバージョンがないのはなぜですか、コンバージョンがないのはなぜですか?イテレータを順方向反復にすることはできますが、逆方向反復はできないのはなぜですか?さらに重要なことは、私がこれをやりたいのであれば、私は何ができますか?フォワードイテレータを使って逆方向に反復することを可能にするアダプタがありますか?逆方向イテレータを順方向イテレータに変換できないのはなぜですか?

std::vector<int> buffer(10); 
std::vector<int>::iterator forward = buffer.begin(); 
std::vector<int>::reverse_iterator backward = buffer.rbegin(); 
++forward; 
++backward; 
std::vector<int>::iterator forwardFromBackward = std::vector<int>::iterator(backward); // error! Can't convert from reverse_iterator to iterator! 
std::vector<int>::reverse_iterator backwardFromForward = std::vector<int>::reverse_iterator(forward); // this is fine 
+14

変換があります: 'backward.base();' – ybungalobill

+0

は、私はあなたが 'reverse_iteratorを使用することができますかなり確信しています'iterator'を使うときはいつでも、iterator型をテンプレート引数として渡すことで必要な場所に置いてください。あなたの問題は解決していませんか? – Grozz

+1

あなたは絶対に正しいybungalobillです。私の実際のコードはこれより少し複雑で、私はbase()を試しましたが、エラーが出て私はそれをあきらめ、私の脳は私の知識を消しました。ありがとう!その正確なテキストを答えとして追加すると、本当に*それは答えですから、私はそれを受け入れます。 –

答えて

15

ヘルパー機能を記述できます。 reverse_iteratorの1つの特殊性は、base()が逆方向反復子が逆参照する値から次に来る順方向反復子を与えることです。 This is because a reverse iterator physically points to the element after the one it logically points to。したがって、reverse_iteratorと同じアイテムにforwardイテレータを設定するには、またはの結果を0より小さくする必要があります。を最初にに増やしてから、.base()を取得してください。

両方の例を以下に示す:

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

//result is undefined if passed container.rend() 
template <class ReverseIterator> 
typename ReverseIterator::iterator_type make_forward(ReverseIterator rit) 
{ 
    return --(rit.base()); // move result of .base() back by one. 
    // alternatively 
    // return (++rit).base() ; 
    // or 
    // return (rit+1).base(). 
} 

int main() 
{ 
    std::vector<int> vec(1, 1); 
    std::vector<int>::reverse_iterator rit = vec.rbegin(); 
    std::vector<int>::iterator fit = make_forward(rit); 
    std::cout << *fit << ' ' << *rit << '\n'; 
} 

警告:この動作は、reverse_iterator(iterator)コンストラクタとは異なっています。

+0

おそらく、make_forward()はポインタ用に特殊化されるべきです。 – Abyx

+0

ybungalobillがrepを望んでいないように見えるので、base()に言及する最初の答えは勝ちます:)ありがとう! –

+0

@Abyx:はい、 'rit.base()'から返された一時ポインタを減らすことはできないので、まず 'iterator_type'という名前の変数を作成する方が良いかもしれません。しかし、専門化は必要ありません。 – visitor

0

あなたはそれが2(リバース)イテレータは(例えばbegin(),end()rbegin(),rend()のように)値の範囲に及ぶ持っていることは非常に一般的です。このコード

container.begin() + (reverseIter - container.rbegin() - 1); 
+0

_Why_。大きなリストの上であなたは過剰なトラバーサルをたくさん求めています。これは単純に '(reverseIter + 1).base()'よりも面倒です。 – bobobobo

+0

どのようなリストですか?それは*ベクトル*です。 – Abyx

+0

イテレータを使用している場合(単純整数インデックスとは対照的に)、イテレータを使用する 'std :: container'にこの数式を適用できるようにする理由があると仮定します。 'std :: list'のトラバースは' std :: vector'よりも高価です。トラバース(1要素のみ)のほうがはるかに優れています。 – bobobobo

1

を用いて逆イテレータから前方イテレータを取得することができます。 2つの逆方向反復子rA,rBで記述されている範囲では、範囲rB.base(),rA.base()は順方向に同じ範囲に広がります。概念的にあなたが(そのようfind_ifの結果として)単一の項目にのみ関心がある場合

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

int main() { 
    std::vector<int> vec{10,11,12,13,14,15}; 

    // spans the range from 13 to 10 
    auto rfirst=std::rbegin(vec)+2; 
    auto rlast=std::rend(vec); 

    // Loops forward, prints 10 11 12 13 
    for(auto it = rlast.base(); it != rfirst.base(); ++it){ 
    std::cout << *it << " "; 
    } 
} 

、その後、@visitorによってmake_forwardを使用しています。この場合であっても、範囲の考え方が逆イテレータの有効性を追跡するのに役立ちます。

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

int main() { 
    std::vector<int> vec{10,11,12,13,14,15}; 

    auto rfirst=std::rbegin(vec); 
    auto rlast=std::rend(vec); 

    auto rfound = std::find_if(rfirst,rlast, [](int v){ return v<13; }); 

    if(rfound != rlast){ 
    std::cout << *rfound << " "; // prints 12 
    auto forwardFound = make_forward(rfound) ; 
    std::cout << *forwardFound << " "; // prints 12 
    } 
} 
関連する問題