Использование boost_foreach без const_iterator - PullRequest
1 голос
/ 13 августа 2011

Есть ли способ использовать boost foreach без определения const_iterator?

Мой вариант использования для этого - итератор для вектора, который может содержать недопустимые элементы. Итератор должен пройти вектор и получить только допустимые элементы. Он также должен восстановить вектор в том смысле, что он должен заменить каждый недопустимый элемент следующим действительным элементом и изменить размер вектора в конце. Например, если -1 представляет недопустимые значения, вектор [6, -1, -1,9, -1,2] должен перебрать 6,9 и 2 и оставить вектор как [6,9,2].

Я пытался реализовать это с boost::iterator_facade, но я не мог придумать, как реализовать const_iterator, потому что вектор может измениться, удалив недопустимые значения, и поэтому не может быть const.

Ответы [ 2 ]

1 голос
/ 13 августа 2011

Разделение задач: контейнер отвечает за свои инварианты, итераторы за обход. Если вы перенесете ремонт в контейнер, вы можете отделить логические const от mutable, скрытых частей.

Можете ли вы написать своим итераторам «глупейший» способ отделить их от контейнера? Например, хранение числового индекса (если это имеет смысл для вашего контейнера), а затем вызов частного друга (или нескольких) контейнера для доступа к логическому n-му элементу.

Личные друзья могут быть перегружены на const и могут по-прежнему изменять mutable детали для выполнения ремонта, который вы описываете, а затем возвращать элемент.


(сокращенный) пример контейнера, поддерживающего произвольный доступ (и, следовательно, числовые индексы для доступа):

template<typename T>
class vector {
    mutable std::vector<std::weak_ptr<T>> data; // notice mutable

    T&
    fetch(int n);

    T const&
    fetch(int n) const; // notice const overload

public:
    class const_iterator;
    friend class const_iterator;

    const_iterator
    begin() const;
};

template<typename T>
class vector<T>::const_iterator {
    int index;
    vector<T> const* this_; // notice const
public:
    // constructors go here

    const_iterator&
    operator++()
    { ++index; }
    // ...

    T const&
    operator*() const
    { return this_->fetch(index); } // this will call the const version of fetch
};

// example implementation of the const version of fetch
template<typename T>
T const&
vector<T>::fetch(int n) const
{
    auto removed = std::remove_if(data.begin(), data.end(), [](std::weak_ptr<T>& element)
    { return element.expired(); });
    // mutate mutable data member in a logically const member
    data.erase(data.begin(), removed);

    // this assumes that there is no race condition
    // bear with me for the sake of understanding the mutable keyword
    return *data[n].lock();
}
0 голосов
/ 13 августа 2011

Все формы «foreach» специально предназначены для итерации по каждому элементу контейнера.Вы не просто итерируете по каждому элементу контейнера.Вы изменяете контейнер во время итерации.

Так что просто напишите обычный цикл for.Нет необходимости в особом уме или чем-либо еще.


Вот код для этого:

std::vector<int> it = vec.begin();
for(; it != vec.end;)
{
  if(*it < 0)
  {
    it = vec.erase(it);
    continue;
  }
  else
  {
    //Do stuff with `it`.
    ++it;
  }
}

Видите, просто простой цикл.Нет необходимости в причудливых фасадах итераторов или других подобных уловках.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...