Это небольшая функция, которая использует предикат.
Для каждого элемента контейнера, который передает предикат, элемент стирается из контейнера.
Нет Перераспределение сделано, и каждый элемент std::move
«d не более одного раза:
template<class C, class F>
void erase_if(C& c, F&& f) {
using std::begin; using std::end;
auto it = std::remove(begin(c), end(c), std::forward<F>(f));
c.erase(it, end(c));
}
Делать это с индексами немного сложнее. Если индексы смежны, вы можете просто повернуть первый в первую позицию, затем удалить хвост контейнера или стереть хвост и фронт, или несколько мириад.
Если это не так, в основном вам нужно написать ручную версию std::remove
, которая работает с индексами вместо значений элементов.
Возможно, это сработает, если у вас есть функция «подсчета», в которой подсчитывается количество элементов, на которые она была вызвана, но полагаться на порядок, который вызывает функция проверки, кажется слишком хрупкой.И remove_by_index
достаточно легко:
template<class Begin, class End, class Test>
void remove_by_index(Begin b, End e, Test t) {
auto writer = b;
auto reader = b;
std::size_t index = 0;
while (reader != e) {
if (t(index)) {
++reader; ++index;
continue;
}
if (reader != writer) {
*writer = std::move(*reader);
}
++reader; ++writer; ++index;
continue;
}
return writer;
}
дает нам:
template<class C, class F>
void erase_by_index(C& c, F&& f) {
using std::begin; using std::end;
auto it = remove_by_index(begin(c), end(c), std::forward<F>(f));
c.erase(it, end(c));
}
Предположим, что вы хотите сохранить срез всех четных позиций элементов:
erase_by_index(vec, [](auto i){return i&1;});
или предположим, что мы хотим сохранить Интервал:
template<class C>
void keep_interval(C& c, std::size_t start_index, std::size_t length) {
erase_by_index(c, [=](auto i){ return i < start_index || i >= (start_index+length); });
}
Теперь более общий способ состоит в создании альтернативного вида вашего контейнера, где каждый элемент в представлении соответствует некоторому диапазону элементов в исходном контейнере, выполняя тесты на этом представлении, а затем применяя операцию на оригинальный контейнер.
Не знаете, как писать это лаконично.
Взгляните на диапазоны и виды eric nieblers: https://github.com/ericniebler/range-v3 Возможно, вы захотите. – midor
стирание первого и последнего элемента? – Slava
Не используйте 'new', как это, ugh. :( – erip