Использование boost::iterator
Я написал разреженный векторный класс (см. № 1, № 2.)
Я хотел бы предоставить два вида итераторов:
Первый набор, обычные итераторы, может указывать на любой элемент, установленный или не заданный. Если они читаются из, они возвращают либо установленное значение, либо value_type()
Если они записаны, они создают элемент и возвращают ссылку lvalue. Таким образом, они являются:
Итератор обхода произвольного доступа и читаемый и записываемый итератор
Второй набор, разреженные итераторы, перебирают только элементы набора. Поскольку им не нужно лениво создавать элементы для записи, они:
Итератор обхода с произвольным доступом, читаемый и записываемый итератор Lvalue
Мне также нужны константные версии обоих, которые не доступны для записи.
Я могу заполнить пробелы, но не уверен, как использовать 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;
1 ответ
Я не уверен, что вы действительно хотите использовать iterator_adaptor
в вашем случае - вы можете использовать iterator_facade
вместо.
Более подробное объяснение: iterator_adaptors
используются, когда у вас есть существующий итератор (скажем, std::list<int>::iterator
) и хотите повторно использовать его поведение для вашего итератора, например. Ваш итератор будет возвращать в два раза больше значения из списка, но повторно использовать код обхода из исходного итератора. Или наоборот: вам может понадобиться итератор, который пропустит некоторые элементы в исходном списке, но вернет значения без изменений. Я не уверен, хотите ли вы основывать свой итератор (как в коде повторного использования) на итераторах ваших базовых структур, но, выступая за меня, я бы не стал особенно в случае не разреженного итератора, поскольку вы, вероятно, захотите создать какой-то прокси для ссылки, что означает, что вы не можете использовать любой итератор dereference()
код, и обход, вероятно, легко. Вы можете, однако, основать свой sparse_iterator
на каком-то итераторе, который перебирает фактически существующие элементы массива, если хотите.
Есть проблемы с прокси-подходом, поэтому не ожидайте, что он будет работать без нареканий, не пройдя через много обручей. С одной стороны, константная версия не разреженного итератора должна все еще возвращать value_type()
, что означает такие выражения, как iter->foo()
следует перевести на value_type().foo()
если соответствующая запись не существует. Но это создает трудности, что pointer_proxy::operator->()
должен вернуть что-то с operator->
желательно указатель (точно нет value_type()
). Что приводит к решающему вопросу: указатель на что? Есть возможность решить эту проблему (например, если ваши объекты управляются boost::shared_pointer
Вы можете просто вернуть shared_pointer
к new
инстанция).
Для не разреженного итератора вам необходимо реализовать:
class reference_proxy
сreference_proxy::operator&
(это, вероятно, вернет указатель прокси)reference_proxy::operator value_type&()
для постоянного использования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
:reference_proxy
Pointer
:pointer_proxy
Разреженная версия проще: если лежащий в основе итератор является разумным (т.е. соответствует поведению, которое вы хотите) и правильно реализован, вы можете просто опустить параметры в iterator_adaptor
(кроме первых двух), и принять все реализации.
Проблема "не компилируется": вставка typename
,