Я записал редкий векторный класс (см. № 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;
Я не уверен, что вы действительно хотите использовать iterator_adaptor
в вашем случае - вместо этого вы можете использовать iterator_facade
.
Более подробное объяснение: iterator_adaptors
используются, когда у вас есть существующий итератор (скажем, std :: list
) и вы хотите повторно использовать его поведение для своих итератор, например. ваш итератор вернет вдвое большее значение, чем в списке, но повторно использует код обхода исходного итератора. Или наоборот: вам может понадобиться итератор, который будет пропускать некоторые элементы в исходном списке, но возвращать значения без изменений. Я не уверен, хотите ли вы основывать свой итератор (как в коде повторного использования) на итераторах ваших базовых структур, но, говоря от себя, я бы не стал особенно в случае неразрезанного итератора, поскольку вы, вероятно, захотите создать некоторые прокси для ссылки, что означает, что вы не можете использовать какой-либо базовый код итератора 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
(кроме первых двух) и возьмем всю реализацию.
Проблема "не компилируется": вставьте имя_типа
.