Подтвердить что ты не робот

Написание итератора, создающего несколько контейнеров, выглядит как один

Рассмотрим следующий упрощенный пример и желаемый результат:

class A
{
    class combined_iterator
    {
        ????
    }
    typedef ??? t_combined_it;

    t_combined_it begin();
    t_combined_it end();

    std::vector<int> m_Vec1, m_Vect2;
}

A a;
a.m_Vec1.push_back(1);
a.m_Vec2.push_back(2);
for (A::t_combined_it it = a.begin() ; it != a.end() ; it++) {
     std::cout << *it << " ";
}

Вывод:

1 2 

Я думаю, что вопрос ясно из этого: как написать итератор, который заставляет его выглядеть так, как если бы два или более других итератора действительно были только одной последовательностью. Таким образом, в примере вместо итерации по m_Vec1 и m_Vec2 я могу использовать итератор, который сначала выполняет итерацию элементов m_Vec1, а затем m_Vec2.

Я нашел следующий вопрос, который, я думаю, спрашивает то же самое: Создайте итератор С++, который пересекает 2 контейнера. Хороших ответов на этот вопрос не было; решение, представленное исходным аскером, кажется запутанным, и оно (относительно) интенсивно используется в памяти.

Я попробовал наивный подход, сохранив std::vector:: iterator как член моего пользовательского итератора и сравнивая его с итераторами .end() каждой из последовательно повторяющихся последовательностей; однако кажется, что сравнивать итераторы с разными контейнерами нецелесообразно (где я бы предпочел, чтобы они просто возвращали "не равно" - может быть, это направление поиска решения этой проблемы? Я не могу придумать, как для его реализации, хотя).

По возможности и, если необходимо, я хотел бы использовать boost:: iterators, поскольку я использую их в другом месте, и мне нравится однородность, которую он предоставляет моим реализациям итератора; но, конечно, если у кого-то есть идея, не используя их, я могу работать с ними в себе, поэтому они не требуются в этом смысле.

4b9b3361

Ответ 1

boost:: join - это то, что вы ищете. Вы также можете изучить реализацию, особенно, как получить самый низкий общий знаменатель для типов обхода контейнеров, ссылочных и возвращаемых значений. Цитировать:

Целью функции соединения является объединение двух диапазонов в один более длинный диапазон.

Результирующий диапазон будет иметь самый низкий общий обход двух диапазонов, представленных в качестве параметров.

Обратите внимание, что объединенный диапазон берет на себя стоимость исполнения из-за необходимости проверять, был ли конец диапазонa > внутренним во время обхода.

Ответ 2

Я думаю, что ваш "наивный" подход должен работать со следующим изменением: вместо сравнения итератора с end() каждого контейнера, удерживайте указатель на текущий контейнер и сравните итератор только с текущим контейнером end(). Когда конец будет достигнут, перейдите к следующему контейнеру. Таким образом, вы никогда не сравните итератор с другим контейнером, чем тот, на который он указывает. Это также легко обобщить на коллекцию коллекций произвольного размера.

Ответ 3

Я уже реализовал нечто похожее для другого вопроса. Реализация здесь. Основная идея - та, к которой вы приблизились: сохранение двух диапазонов итераторов, когда вас попросят выполнить операцию, проверьте, завершили ли вы итерацию в первом диапазоне, и используйте любой диапазон.

Это не потокобезопасно, и я никогда не использовал эту реализацию в реальном коде, поэтому могут возникнуть проблемы и ошибки и...

Ответ 4

zip_iterator работает, если вы хотите параллельно итерации двух итераторов. Если вам нужно последовательно перебирать контейнеры, вы можете, возможно, реализовать его с помощью iterator_adaptor.

Ответ 5

Ответы других людей дали только работу по объединению диапазонов два, но не произвольное количество диапазонов.

PStade Oven имеет адаптер concatenated для соединения любого количества диапазонов; он также имеет адаптер jointed для соединения двух диапазонов, в частности.

Вы можете, конечно, включить диапазоны в итераторы с begin() и end(), если это необходимо; просто убедитесь, что диапазоны превышают итераторы.

Ответ 6

Aasmund прав. Ваш подход, хотя и простой, должен работать. Но есть много возможностей для оптимизации.

Объекты коллекции часто бывают большими, и для этого требуется некоторое время для повторения. Особенно список и массивы.

Вы должны рассмотреть многопоточность, чтобы каждая коллекция могла повторяться параллельно.

Дополнительно. Вы должны принять совет от сообщения, которое вы использовали для использования и использования

Boost.MultiIndex