0

(注: 私はこのプロジェクトを学習用に書いています。冗長であるというコメントは...ええと、冗長です。;)

私はランダム アクセス イテレータを実装しようとしていますが、このテーマに関する文献はほとんど見つかりませんでした。そのため、Wikpedia のオペレータ オーバーロード プロトタイプのリストと組み合わせて試行錯誤を繰り返しています。これまでのところ十分に機能していますが、問題が発生しました。

次のようなコード

exscape::string::iterator i = string_instance.begin();
std::cout << *i << std::endl;

機能し、文字列の最初の文字を出力します。ただし、*(i + 1) は機能せず、*(1 + i) も機能しません。私の完全な実装は明らかに少し多すぎますが、その要点は次のとおりです。

namespace exscape {
    class string {
        friend class iterator;
    ...
    public:
        class iterator : public std::iterator<std::random_access_iterator_tag, char> {
            ...
            char &operator*(void) {
                return *p; // After some bounds checking
            }
            char *operator->(void) {
                return p;
            }

            char &operator[](const int offset) {
                return *(p + offset); // After some bounds checking
            }

            iterator &operator+=(const int offset) {
                p += offset;
                return *this;
            }

            const iterator operator+(const int offset) {
                iterator out (*this);
                out += offset;
                return out;
            }

        };
};
}

int main() {
    exscape::string s = "ABCDEF";
    exscape::string::iterator i = s.begin();
    std::cout << *(i + 2) << std::endl;
}

上記は失敗します (632 行目はもちろん *(i + 2) 行です):

string.cpp: 関数 'int main()': string.cpp:632: エラー: '*exscape::string::iterator::operator+(int)(2)' 文字列の 'operator*' に一致しません。 cpp:105: 注: 候補は: char& exscape::string::iterator::operator*()

*(2 + i) は以下で失敗します:

string.cpp: 関数 'int main()' 内: string.cpp:632: エラー: '2 + i' の 'operator+' に一致しません string.cpp:434: 注: 候補は: exscape::string exscape: :operator+(const char*, const exscape::string&)

私の推測では、さらにオーバーロードを行う必要がありますが、どの演算子が欠けているのかわかりません。

4

4 に答える 4

9

演算子は const イテレータを返しますが、 const がありませ+operator*。1つ追加してください。大丈夫だと思います。または、以下の xtofl で提案されているように、operator*const を作成できます。operator*何らかの理由で非 const が本当に必要でない限り、それはより良い設計です。

于 2009-11-10T17:00:18.063 に答える
4

左側の数値定数で機能させるには、非メンバー関数が必要です。このようなもの(テストされていないコード):

exscape::string::iterator operator+(exscape::string::iterator it, size_t n) {
    return it += n;
}

exscape::string::iterator operator+(size_t n, exscape::string::iterator it) {
    return it += n;
}
于 2009-11-10T17:05:07.900 に答える
3

まず、 が必要ですoperator *(void) const

[編集: 既存のオペレーターに基づいて、次のようにする必要があります。

char &operator *(void) const {
    // bounds checking
    return *p;
}

]

次に、 が必要ですoperator+(int, exscape::string::iterator)。これを記述するかなり一般的な方法は、(イテレータ クラスで) 次のようになります。

friend const iterator operator+(const int offset, iterator out) {
    out += offset;
    return out;
}

クラス内で定義されていても、フレンドとしてマークすると非メンバー関数になることに注意してください。+ の LHS と RHS に同じ暗黙の変換規則が適用されるように、 をoperator+(int)非メンバー関数に置き換えることもできます。operator+(iterator,int)

[別の編集: コメントで指摘したように、operator+ はconst iteratorとにかく返すべきではありません - ただ return iterator. したがって、コード例では、実際には必要ありませんoperator*()const。ただし、ユーザーはクラスの const で変更されたインスタンスを使用してコードを記述したい場合があるため、とにかく 1 つ持つ必要があります。]

最後に、ランダム アクセス反復子 (std::string を含む) を持つ標準コンテナーdifference_typeは、クラスのメンバーとして signed を定義します。intすべての可能なオフセットを含めるには十分な大きさではない可能性がありますが (LP64 アーキテクチャーなど)、ptrdiff_t適切な候補です。

于 2009-11-10T17:07:02.357 に答える
0

左辺のオペランドは独自の型である必要があるため、 *(2 + i) が機能するとは思いません。実際には、イテレータを 2 に追加するようにコンパイラに指示していますが、これは意味がありません。(i + 2) は、イテレータを 2 つのインデックスに移動することを意味します。

詳細については、C++ Faq Liteを参照してください。

于 2009-11-10T17:06:09.993 に答える