11

疎なベクトル クラスを作成しました ( #1#2を参照してください)。

2 種類の反復子を提供したいと思います。

最初のセットである通常の反復子は、設定されているかどうかに関係なく、任意の要素を指すことができます。それらが読み取られた場合は、セット値を返すか、value_type()書き込まれた場合は、要素を作成して左辺値参照を返します。したがって、それらは次のとおりです。

ランダム アクセス トラバーサル イテレータ読み取り可能および書き込み可能なイテレータ

2 番目のセットであるスパース反復子は、セット要素のみを反復処理します。書き込まれる要素を遅延して作成する必要がないため、次のようになります。

ランダム アクセス トラバーサル イテレータおよび読み取り可能書き込み可能​​左辺値イテレータ

また、書き込み不可の両方の const バージョンも必要です。

空白を埋めることはできますが、boost::iterator_adaptor を使用して開始する方法がわかりません。

これが私がこれまでに持っているものです:

template<typename T>
class sparse_vector {
public:
    typedef size_t size_type;
    typedef T value_type;

private:
    typedef T& true_reference;
    typedef const T* const_pointer;
    typedef sparse_vector<T> self_type;
    struct ElementType {
        ElementType(size_type i, T const& t): index(i), value(t) {}
        ElementType(size_type i, T&& t): index(i), value(t) {}
        ElementType(size_type i): index(i) {}
        ElementType(ElementType const&) = default;
        size_type index;
        value_type value;
    };
    typedef vector<ElementType> array_type;

public:
    typedef T* pointer;
    typedef T& reference;
    typedef const T& const_reference;

private:
    size_type                                   size_;
    mutable typename array_type::size_type      sorted_filled_; 
    mutable array_type                          data_;

// lots of code for various algorithms...

public:    
    class sparse_iterator
        : public boost::iterator_adaptor<
          sparse_iterator                   // Derived
          , typename array_type::iterator            // Base (the internal array)
          , value_type              // Value
          , boost::random_access_traversal_tag    // CategoryOrTraversal
          > {...}

    class iterator_proxy {
          ???
    };

    class iterator
        : public boost::iterator_facade<
          iterator                          // Derived
          , ?????                           // Base
          , ?????              // Value
          , boost::??????    // CategoryOrTraversal
          > {
    };
};

また、これは違法ですか?

typedef boost::reverse_iterator<sparse_iterator> reverse_sparse_iterator;
4

1 に答える 1

19

あなたのケースで本当に使いたいかどうかはわかりませんiterator_adaptor-代わりに使いたいかもしれませんiterator_facade

より完全な説明:iterator_adaptors既存のイテレータ (たとえばstd::list<int>::iterator) があり、その動作をイテレータに再利用したい場合に使用されます。イテレータはリストにある値の 2 倍の値を返しますが、元のイテレータのトラバーサル コードを再利用します。またはその逆: 元のリストの一部の要素をスキップするイテレータが必要になる場合がありますが、値は変更されずに返されます。基礎となる構造のイテレーターに基づいてイテレーターを (再利用コードのように) 使用するかどうかはわかりませんが、非スパース イテレーターの場合は特に作成したくないと思います。つまり、基になる反復子コードを使用できずdereference()、トラバーサルはおそらく簡単です。ただし、ベースにすることはできますsparse_iterator必要に応じて、配列の実際に存在する要素を反復処理するイテレータ。

プロキシ アプローチには問題があるため、多くの手間をかけずに問題なく動作するとは思わないでください。1 つには、非スパース イテレータの const バージョンは引き続き を返す必要があります。これは、対応するエントリが存在しない場合、 のような式が に変換されるvalue_type()ことを意味します。しかし、これは困難をもたらします。それは、できればポインターで何かを返す必要があります(間違いなく ではありません)。これは、重要な質問につながります。何へのポインタですか? これを解決する可能性があります (たとえば、オブジェクトを で管理している場合は、 を'd インスタンスに戻すことができます)。iter->foo()value_type().foo()pointer_proxy::operator->()operator->value_type()boost::shared_pointershared_pointernew

非スパース反復子の場合、次を実装する必要があります。

  • class reference_proxy
  • reference_proxy::operator&(おそらくポインタープロキシを返します)
  • reference_proxy::operator value_type&()const 用
  • reference_proxy::operator const value_type&()const 以外の用途
  • reference_proxy::foo()value_typefoo()のメンバー関数の場合 (そうでない場合、AFAIK のような式は機能し(*it).foo()ません)

  • class pointer_proxy

  • pointer_proxy::operator*(reference_proxy を返す)
  • pointer_proxy::operator->(賢明なことをしてください、上記を参照してください)

イテレータ ファサード テンプレートのパラメータは次のとおりです。

  • Referencereference_proxy
  • Pointerpointer_proxy

スパース バージョンはより単純です。基になるイテレータが適切で (つまり、必要な動作に一致し)、適切に実装されている場合は、iterator_adaptor(最初の 2 つを除いて) へのパラメーターを省略し、すべての実装を取得できます。

「コンパイルしない」問題: insert typename.

于 2010-05-12T21:56:57.580 に答える