Используйте reverse_iterator с удалением типа

У меня есть класс, который содержит и управляет серией объектов. Чтобы не допустить утечки информации о том, как эти объекты хранятся, а затем перебирать их, я решил использовать стирание типа, используя boost::any_iterator,

 using my_erased_type_iterator = boost::range_detail::any_iterator<
MyClass,
boost::bidirectional_traversal_tag,
MyClass&,
std::ptrdiff_t>;

Я определил функцию Begin() а также End() в MyClass, который просто возвращает контейнер begin() а также end() функционировать как my_erased_type_iterator, Это работает именно так, как я хочу, и никто за пределами MyClass знает, что я использую вектор для хранения объектов, и при этом они не имеют доступа к контейнеру, кроме функций, которые я предоставляю в MyclassИнтерфейс.

Теперь по ряду причин мне нужно выполнить итерацию по объектам. Мне также нужно знать следующий элемент после обратного итератора (сродни вызову std::next() на обычном итераторе, что уже не так тривиально для обратных итераторов), и мне также может понадобиться вызвать функции, такие как erase() на этом обратном итераторе.

Итак, на мой вопрос: существует ли элегантный способ использовать стирание типов вместе с обратными итераторами (и const-версия для прямого и обратного)? Должен ли я использовать итераторы со стертым типом вперед и вместо этого выполнять итерацию назад? Мне пришло в голову, что я могу заняться этой проблемой неправильно, поэтому я открыт для любых предложений или для уточнения своих вопросов, если это необходимо.

4

Решение

Обратите внимание, что any_iterator это деталь реализации.

Сначала я отвечу на ваш прямой вопрос, а затем покажу any_range<> как и задумано публичным API Boost Range.

1. make_reverse_iterator

Вы можете просто использовать make_reverse_iterator средство от

Жить на Колиру

#include <boost/range.hpp>
#include <boost/range/any_range.hpp>

struct MyClass {
int i;
};

using my_erased_type_iterator = boost::range_detail::any_iterator<
MyClass,
boost::bidirectional_traversal_tag,
MyClass&,
std::ptrdiff_t>;

#include <iostream>
#include <vector>

int main() {
using namespace boost;
std::vector<MyClass> const v { {1}, {2}, {3}, {4} };

for (auto& mc : make_iterator_range(
make_reverse_iterator(v.end()),
make_reverse_iterator(v.begin())))
{
std::cout << mc.i << " ";
}
}

Печать

4 3 2 1

2. reversed адаптер диапазона:

Кроме того, вы можете перейти на полный диапазон стиля и использовать any_range<>:

Жить на Колиру

int main() {
std::vector<MyClass> const v { {1}, {2}, {3}, {4} };

boost::any_range_type_generator<decltype(v)>::type x = reverse(v);

for (my_erased_type_const_iterator f = boost::begin(x), l = boost::end(x); f!=l; ++f) {
std::cout << f->i << " ";
}

}
1

Другие решения

Просто поменяйте местами стертые итераторы.

Это разоблачает .base()Это означает, что стирание почти так же просто, как стирание типа стертых вперед.

Кроме того, ваш дизайн имеет затраты производительности для (по моему опыту) предельной выгоды. Итерация для правил invalidadion базового контейнера все еще применяется, поэтому пользователь вашего класса должен знать, что такое базовый контейнер! (Или знайте так много, они могли бы также). Выгрузка контейнера не обеспечит достаточно похожего поведения, поэтому ваш контейнер заблокирован, несмотря на ваши достаточно дорогие попытки его скрыть.

1

По вопросам рекламы [email protected]