Повторение по контейнеру двунаправленно


Есть ли лучший способ, чем приведенный ниже код, перебирать контейнер в любом направлении, используя одни и те же итераторы?

#include <iostream>
#include <map>

int main()
{
    const bool descend = false;

    std::map<int, int> mapp;
    mapp[1] = 1;
    mapp[2] = 2;
    mapp[3] = 3;
    mapp[4] = 4;

    std::map<int, int>::iterator startIter = descend ? --(mapp.end()) : mapp.begin();
    std::map<int, int>::iterator endIter = descend ? --(mapp.begin()) : mapp.end();

    while (startIter != endIter)
    {
        std::cout << startIter->first << std::endl;
        descend ? --startIter : ++startIter;
    }
}
3 2

3 ответа:

Ваш код недействителен, так как это утверждение --(mapp.begin()) приводит к UB. Я бы написал тонкую обертку:

template<class Iter, class F>
void apply( Iter begin, Iter end, F f, bool forward )
{
    while( begin != end ) 
        f( forward ? *begin++ : *--end );
}

Живой пример

Или просто перепишите свой цикл в:

auto begin = mapp.begin();
auto end = mapp.end();
while ( begin != end)
{
    const auto &p = forward ? *begin++ : *--end;
    std::cout << p.first << std::endl;
}

Есть ли лучший способ, чем приведенный ниже код, для итерации по контейнеру в любом направлении, используя одни и те же итераторы?

Да . Используйте std::map::reverse_iterator. Это будет лучше, чем код, который вы опубликовали, но это больше не будет использовать те же итераторы, что было одним из ваших требований.

Однако это будет менее подвержено ошибкам, чем написанный вами код. Кроме того, вам не нужно заново изобретать колесо, если оно уже есть в C++.

смотрите вывод здесь

#include <iostream>
#include <map>

template<typename Iterator>
void print(const Iterator Begin, const Iterator End)
{
    for(Iterator iter = Begin; iter != End; ++iter)
       std::cout << iter->first << "\n";
}

int main()
{
    const bool descend = true;

    std::map<int, int> mapp;
    mapp[1] = 1;
    mapp[2] = 2;
    mapp[3] = 3;
    mapp[4] = 4;

    descend ?
        print(mapp.crbegin(), mapp.crend()):
        print(mapp.cbegin(), mapp.cend());
    return 0;
}

Изображение из cppreference.com объяснит графически, как это работает. Введите описание изображения здесь

Напишите самодокументируемый код, и он станет простым. Разбейте этот цикл на его собственную функцию и вызовите ее с помощью соответствующих итераторов.

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

#include <iostream>
#include <map>

template<typename I>
void printMapContainer(I begin, I end)
{
    for (;begin != end; ++begin)
    {
        std::cout << begin->first << "\n";
    }
}
int main()
{
    const bool descend = false;

    std::map<int, int> mapp;
    mapp[1] = 1;
    mapp[2] = 2;
    mapp[3] = 3;
    mapp[4] = 4;

    if (descend) {
        printMapContainer(mapp.rbegin(), mapp.rend());
    }
    else {
        printMapContainer(mapp.begin(), mapp.end());
    }
}