Используя повышение:: итератор

Я записал редкий векторный класс (см. № 1, № 2.)

Я хотел бы обеспечить два вида итераторов:

Первый набор, регулярные итераторы, может указать на любой элемент, или установить или сбросить. Если они читаются из, они возвращают или установленное значение или value_type(), если они записаны в, они создают элемент и возвращают lvalue ссылку. Таким образом они:

Итератор обхода произвольного доступа и читаемый и перезаписываемый итератор

Второй набор, редкие итераторы, выполняет итерации только по элементам набора. Так как они не должны лениво создавать элементы, которые записаны в, они:

Итератор обхода произвольного доступа и читаемый и перезаписываемый и итератор Lvalue

Мне также нужны версии константы обоих, которые не перезаписываемы.

Я могу восполнить пробелы, но не уверенный, как использовать повышение:: iterator_adaptor для начинаний.

Вот то, что я имею до сих пор:

template
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 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 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 reverse_sparse_iterator;

11
задан Community 23 May 2017 в 11:58
поделиться

1 ответ

Я не уверен, что вы действительно хотите использовать iterator_adaptor в вашем случае - вместо этого вы можете использовать iterator_facade .

Более подробное объяснение: iterator_adaptors используются, когда у вас есть существующий итератор (скажем, std :: list :: iterator ) и вы хотите повторно использовать его поведение для своих итератор, например. ваш итератор вернет вдвое большее значение, чем в списке, но повторно использует код обхода исходного итератора. Или наоборот: вам может понадобиться итератор, который будет пропускать некоторые элементы в исходном списке, но возвращать значения без изменений. Я не уверен, хотите ли вы основывать свой итератор (как в коде повторного использования) на итераторах ваших базовых структур, но, говоря от себя, я бы не стал особенно в случае неразрезанного итератора, поскольку вы, вероятно, захотите создать некоторые прокси для ссылки, что означает, что вы не можете использовать какой-либо базовый код итератора dereference () , и переход, вероятно, будет простым. Однако вы можете основать свой sparse_iterator на каком-нибудь итераторе, который выполняет итерацию по фактически существующим элементам массива, если хотите.

Есть проблемы с подходом прокси, поэтому не ожидайте, что он будет работать безупречно, не пройдя через множество препятствий. Во-первых, константная версия неразложенного итератора должна по-прежнему возвращать value_type () , что означает, что выражения типа iter-> foo () должны преобразовываться в value_type (). foo () , если соответствующая запись не существует.Но это создает трудность, так как pointer_proxy :: operator -> () должен возвращать что-то с оператором -> , предпочтительно указатель (определенно не value_type () ). Это приводит к решающему вопросу: указатель на что? Есть возможности решить эту проблему (например, если у вас есть объекты, управляемые с помощью boost :: shared_pointer , вы можете просто вернуть shared_pointer в new ' г).

Для итератора с неразложенным анализом необходимо реализовать:

  • класс reference_proxy с
  • reference_proxy :: operator & (который, вероятно, вернет прокси-указатель)
  • reference_proxy :: operator value_type & ( ) для const использует
  • reference_proxy :: operator const value_type & () для неконстантных использует
  • reference_proxy :: foo () для любого члена foo () функция value_type (в противном случае выражения типа (* it) .foo () AFAIK не будут работать)

  • class pointer_proxy с

  • pointer_proxy :: operator * (вернуть reference_proxy)
  • pointer_proxy :: operator -> (сделайте что-нибудь разумное, см. выше)

Параметры для шаблона фасада итератора должны быть:

  • Ссылка : reference_proxy
  • Указатель : pointer_proxy

Разреженная версия проще: если базовый итератор разумный (т.е. соответствует желаемому поведению) и правильно реализован, вы можете просто опустить параметры к iterator_adaptor (кроме первых двух) и возьмем всю реализацию.

Проблема "не компилируется": вставьте имя_типа .

19
ответ дан 3 December 2019 в 06:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: