5

OK、それで私は今イテレータを使っている2つの(完全に無関係な、異なるプロジェクト)クラスを持っています。1つは意図したとおりに機能し、もう1つは現在のものがiteratorあり、半壊しています(具体的には、const_iteratorはイテレーターから派生しているため、コードは有効であり、const定義リストを変更できます...)。 このクラスに4つのタイプすべてを追加するつもりです...可能であれば。 reverse_iteratoriteratorconst_iteratorLinkedList<int>::iterator i = const_list.begin()

コードのコピー/貼り付けを最小限に抑え、リターンタイプのみを変更するにはどうすればよいですか?base_iterator継承したい基本クラスを作成しますか?iteratorまたはを作成し、const_iteratorそれから継承しますか?いくつかのstd::クラスから継承しますか?これらのケースのいずれかが「最良の」アプローチである場合、どのコードがどこに行きますか?
おそらく、選択肢のどれも良いものではありませんか?私はここでかなり迷っていて、多くの参考資料を見つけることができません。

アドバイスをいただければ幸いですが、私はこのテーマに慣れていないことを覚えておいてください(イテレーターとC ++の両方、特にOOP)。私は無駄に、GCCに付属しているヘッダーファイルを調べようとしましたが、それらは私が探しているチュートリアルではありません。

4

6 に答える 6

3

場合によっては、いわゆるDRYルール(慣れていない人のために、自分を繰り返さないでください)を包括的に適用することが最善のアプローチではないことがあります。特に、言語(C ++とイテレーター)とOOP自体(方法論)に慣れていない場合は、今すぐ作成する必要のあるコードの量を最小限に抑えようとしても、ほとんどメリットがありません。

それぞれに適切なコードを使用して、2つのイテレータを実装します。おそらく、言語、ツール、および技法についてより多くの経験を積んだ後、戻って、一般的なコードを除外することによってコードの量を減らすことができるかどうかを確認してください。

于 2009-11-21T20:22:27.903 に答える
3

それは実際には非常に簡単です。

まず、Boost.Iteratorライブラリを見てください。

次に、これに似た基本クラスを宣言する必要があります(手順の例で詳しく説明されています)。

template <class Value>
class BaseIterator: boost::iterator_adaptor< ... > {};

ポインタをそこに移動する操作を実装します。これは既存のイテレータを適応させたものであるため、数回のストロークで実装できることに注意してください。本当に印象的です。

第三に、constバージョンとnon-constバージョンを使用してtypedefを実行するだけです。

typedef BaseIterator<Value> iterator;
typedef BaseIterator<const Value> const_iterator;

ライブラリは、const_iteratorバージョンをバージョンから構築可能にする方法を明示的に示していますiterator

第4に、逆の場合、通常のイテレータ上に構築され、後方に移動する特別なreverse_iteratorオブジェクトがあります:)

全体として、カスタムクラスでイテレータを定義するための非常にエレガントでありながら完全に機能的な方法です。

私は定期的に自分のコンテナアダプターを作成していますが、タイピングを節約するよりもDRYの方が重要です。

于 2009-11-23T08:15:16.463 に答える
1

逆ではなく、イテレータをconst_iteratorから派生させます。適切に使用const_castします(実装の詳細として、ユーザーに公開されません)。これは、「イテレータはconst_iteratorsである」という単純なケースやモデルで非常にうまく機能します。

これでコードに説明コメントが必要になり始めたら、別のクラスを作成します。ローカライズされたマクロを使用して同様のコードを生成し、ロジックの繰り返しを回避できます。

struct Container {
#define G(This) \
This& operator++() { ++_internal_member; return *this; } \
This operator++(int) { This copy (*this); ++*this; return copy; }

  struct iterator {
    G(iterator)
  };
  struct const_iterator {
    G(const_iterator)
    const_iterator(iterator); // and other const_iterator specific code
  };
#undef G
};

マクロがスコープ/ローカライズされていることは重要です。もちろん、実際に役立つ場合にのみ使用してください。コードが読みにくくなる場合は、明示的に入力してください。

そして、逆イテレータについて:std::reverse_iterator多くの場合、「通常の」イテレータを書き換える代わりに、それらをラップするために使用できます。

struct Container {
  struct iterator {/*...*/};
  struct const_iterator {/*...*/};

  typedef std::reverse_iterator<iterator> reverse_iterator;
  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
};
于 2009-11-21T21:19:48.270 に答える
0

LinkedList<int>::iterator i = const_list.begin()あなたのbeginメソッドはどのように見えますか?STLを調べると、コンテナが次のシグネチャを持つ2つのそのようなメソッドを定義していることがわかります。

const_iterator begin() const;
iterator begin();

iteratorconstとして修飾されたオブジェクトからを取得するのに問題はないはずです。ここではDRYは当てはまらないと思います。

于 2009-11-21T21:13:26.037 に答える
0

次のアプローチを使用した後:

  1. テンプレートクラスをcommon_iteratorにする
  2. 「iterator」と「const_iterator」のtypedefを追加します
  3. 「common_iterator」に「iterator」タイプのコンストラクターを追加します

「イテレータ」の場合、追加のコンストラクターがデフォルトのコピーコンストラクターに置き換わります。私の場合は、デフォルトのコピーコンストラクターと同等でした。

「const_iterator」の場合、「iterator」から「const_iterator」を構築できる追加のコンストラクターになります。

于 2009-11-21T21:57:19.617 に答える
0

maxim1000が提案したもののより具体的なバージョン:

#include <type_traits>

template<typename Container, bool forward>
class iterator_base
{
public:
    using value_type =
        typename std::conditional<std::is_const<Container>::value,
                                 const typename Container::value_type,
                                 typename Container::value_type>::type;

    iterator_base() { }

    // For conversions from iterator to const_iterator.
    template<typename U>
    iterator_base(const iterator_base<U, forward>& other)
    : c(other.c)
    {
        // ....
    }

    value_type& operator*() const
    {
        // ...
    }

    iterator_base& operator++()
    {
        if (forward)
        {
            // ...
        }
        else
        {
            // ...
        }
    }

    iterator_base& operator++(int)
    {
        iterator_base copy(*this);
        ++*this;
        return copy;
    }

private:
    Container* c = nullptr;
    // ...
};

using iterator = iterator_base<self_type, true>;
using const_iterator = iterator_base<const self_type, true>;

using reverse_iterator = iterator_base<self_type, false>;
using const_reverse_iterator = iterator_base<const self_type, false>;
于 2017-08-21T18:28:35.523 に答える