Повторение по контейнеру двунаправленно
Есть ли лучший способ, чем приведенный ниже код, перебирать контейнер в любом направлении, используя одни и те же итераторы?
#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 ответа:
Ваш код недействителен, так как это утверждение
--(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; }
Есть ли лучший способ, чем приведенный ниже код, для итерации по контейнеру в любом направлении, используя одни и те же итераторы?
Да . Используйте
Однако это будет менее подвержено ошибкам, чем написанный вами код. Кроме того, вам не нужно заново изобретать колесо, если оно уже есть в C++.std::map::reverse_iterator
. Это будет лучше, чем код, который вы опубликовали, но это больше не будет использовать те же итераторы, что было одним из ваших требований.#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()); } }