Цикл требует выполнять перебор до конца входного диапазона данных. Во время каждой итерации вызов std::find
split_val
. В нашем случае этот элемент — дефис ('-'
), поскольку мы хотим разбить входную строку на фрагменты, находящиеся между дефисами. Следующая позиция дефиса теперь сохраняется в slice_end
. После перебора цикла итератор it
перемещается на следующий после искомого элемент. Таким образом, цикл перескакивает от дефиса к дефису вместо того, чтобы проходить по отдельным элементам.В данной комбинации итератор it
slice
, а slice_end
— на конец последней вырезки. Оба итератора отмечают начало и конец поддиапазона данных, который представляет собой ровно одну вырезку между двумя символами дефиса. Для строки "foo-bar-baz"
это значит, что у нас будет три итерации цикла и всякий раз мы будем получать пару итераторов, которые окружают одно слово. Но нам нужны не итераторы, а подстроки. Бинарная функция bin_func
помогает их получить. При вызове функции split
мы передали ей следующую бинарную функцию:[](auto it_a, auto it_b) {
return string(it_a, it_b);
}
Функция split
bin_func
, прежде чем отправить их в конечный итератор. От функции bin_func
мы получим строки "foo"
, "bar"
и "baz"
.Дополнительная информация
Интересной альтернативой реализации нашего алгоритма, разбивающего строки на части, является реализация
Этот итератор должен перескакивать между разделителями при каждом инкременте. При разыменовании ему следует создавать объект строки на основе позиции, на которую он сейчас указывает, что можно сделать с помощью бинарной функции binfunc
Если бы наш класс итератора назывался split_iterator
split
, то код пользователя выглядел бы так:string s {"a-b-c-d-e-f-g"};
list
auto binfunc ([](auto it_a, auto it_b) {
return string(it_a, it_b);
});
copy(split_iterator{begin(s), end(s), '-', binfunc},{}, back_inserter(l));
Недостатком описанного подхода служит тот факт, что реализовать итератор сложнее, чем одну функцию. Кроме того, существует множество узких моментов в коде итератора, которые могут привести к появлению ошибок, поэтому такое решение требует более серьезного тестирования. С другой стороны, очень легко объединить подобный итератор с другими алгоритмами библиотеки STL.
Создаем полезные алгоритмы на основе стандартных алгоритмов gather
Алгоритм gather
Алгоритм gather
Как это делается
В данном примере мы реализуем алгоритм gather
1. Сначала добавим все выражения include
std
:#include
#include
#include
#include
using namespace std;
2. Алгоритм gather
gather_pos
, который указывает на какую-то позицию между ними. Последний параметр — функция-предикат. С ее помощью алгоритм поместит все элементы, соответствующие заданному условию, в позиции рядом с итератором gather_pos
. Реализация перемещения элементов выполняется благодаря std::stable_partition
. Алгоритм gather
возвращает пару итераторов. Они возвращаются вызовом stable_partition
и, таким образом, отмечают начало и конец полученного диапазона:template
pair
{
return {stable_partition(first, gather_pos, not_fn(predicate)),
stable_partition(gather_pos, last, predicate)};
}