2

標準のコンテナメンバーを持つクラスがありますが、特定のルートを使用して独自のイテレータを作成することは可能でしょうか。たとえば、行き来して、その後停止します。

template<class T>
class compressed_string {
    vector<T> v;
public:
    typedef typename std::vector<T>::iterator iterator;
    iterator begin() { return v.begin(); }
    iterator end() { return v.end(); }

    compressed_string& add(const T& elem) {
        v.push_back(elem);
        return *this;
    }
    basic_string<T> not_nice_way_to_make_real_string() {
        basic_string<T> tmp;
        for(iterator i = v.begin(); i < v.end(); ++i)
            tmp += *i;
        for(iterator i = --v.end(); i >= v.begin(); --i)
            tmp += *i;
        return tmp;
    }
};

主要:

compressed_string<char> s;
s.add('q').add('w').add('e').add('w');

cout << s.not_nice_way_to_make_real_string(); // q w e w w e w q

cout << endl

for ( compressed_string<char>::iterator i = s.begin(); i < s.end(); ++i )
    cout << *i;

したがって、このイテレータメンバーを使用すると、出力はこの2行で同じになります。

これはどのように可能ですか?

4

1 に答える 1

2

少しの状態を格納するイテレータが必要です。

  • v_itそれがどこにあるか(例えば、上のイテレータv
  • どこに行くのか(例bool forward
  • 有界の場所(例:イテレータv_begin = v.begin()v_end = v.end()

)など、終了を表す無効なイテレータもあります{v_end, backward}

次に、次の行に沿ってインクリメント演算子を実装します。

if (forward) {
    if (++v_it == v_end) {
        forward = false;
        --v_it;
    }
} else {
    if (v_it-- == v_begin) {
        v_it = v_end;
    }
}

双方向イテレータが必要な場合は、デクリメントについても同様です。その場合、それも提供するのは礼儀正しいでしょうreverse_iterator。インクリメント前とインクリメント後の両方のフォームを提供する必要があります。

==また、と!=の比較、との両方の比較、v_itおよびforward間接参照演算子*->その間接参照v_it、および適切な関数も必要にbeginなります。endボーナスポイントについては、aconst_iteratorがいいでしょう。

i < s.end()質問のコード(より一般的なものではなく)を本当に機能させたい場合は、ランダムアクセスが必要になることに注意してくださいi != s.end()。それは完全に可能ですが、他の方法でそれを必要としない場合はかなり過剰です。

更新:コメントに記載されているように、この特定の実装はおそらく少し改善される可能性があります。たとえば、v_beginエンドイテレータの定義方法に少し注意を払えば、保存する必要がなくなる可能性があります。

于 2013-01-21T19:03:58.647 に答える