Елегантен начин за условно повторение напред или назад

Трябва да обработя std::vector или напред, или назад, в зависимост от булев флаг. Кой е най-елегантният начин да постигнете това? Преди да се наложи да го направя наобратно, имах:

BOOST_FOREACH(const CType &foo, vec) {
    ...
}

Сега обаче имам ужасно изглеждащото:

for (int i=undoing ? (vec.size()-1) : 0; undoing ? (i >= 0) : (i < vec.size()); undoing ? (i--) : (i++)) {
    const CType &foo = vec[i];
    ...
}

Има ли по-добър начин?


person Claudiu    schedule 15.04.2014    source източник
comment
Поддръжка на C++11? Предполагам, че не.   -  person Yakk - Adam Nevraumont    schedule 16.04.2014
comment
@Yakk: Не, въпреки че все пак ще ми е интересно да видя този отговор.   -  person Claudiu    schedule 16.04.2014
comment
минимално опростяване на вашия код за (unsigned i=undoing ? (vec.size()-1) : 0; i ‹ vec.size(); undoing ? (i--) : (i++))   -  person Alexander    schedule 16.04.2014
comment
Моля, вижте stackoverflow.com/questions/22360697/   -  person 101010    schedule 16.04.2014


Отговори (4)


Не знам дали хората биха го нарекли елегантно, но има:

auto do_it = [](const CType& elem)
             {
                 ...
             };
if (iterate_forward) {
    std::for_each(vec.begin(), vec.end(), do_it);
}
else {
    std::for_each(vec.rbegin(), vec.rend(), do_it);
}
person Max Lybbert    schedule 15.04.2014
comment
О, интересно. Предпочитам това пред отговора с най-високо одобрение, тъй като не трябва сам да внедрявам частта от цикъла. - person Claudiu; 16.04.2014
comment
Да, съгласен съм, че е по-добре. Трябва да използвате STL алгоритмите, когато е възможно. Разбира се, ламбда изразът може да бъде заменен от унарна функция, за да работи с C++98 компилатор. - person Adam Wulkiewicz; 16.04.2014

Добавете шаблонна функция, която работи с итератори напред или с обратни итератори. Извикайте функцията, като използвате подходящия итератор въз основа на стойността на undoing.

template <typename Iterator>
void doStuff(Iterator iter, Iterator end)
{
   for ( ; iter != end; ++iter )
   {
      // Do stuff
   }
}

if ( undoing )
{
   doStuff(vec.rbegin(), vec.rend());
}
else
{
   doStuff(vec.begin(), vec.end());
}
person R Sahu    schedule 15.04.2014

Какво ще кажете за запазване на цикъла, тъй като е от 0 до vector.size, но четене на масива в посоката, от която се нуждаете.

int idx;
for (int i =0; i < vec.size(); i ++)
{
   if (undoing) // assuming going forward
     idx = i;
   else // going backwards
     idx = vec.size() - i - 1;

  const CType &foo = vec[idx];
}
person user3494754    schedule 15.04.2014

Можете също така да използвате базирано на Boost.Range решение. Той е подобен на този, използващ STL алгоритми, вече предложен.

#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/algorithm/for_each.hpp>

// In C++11 lambda expression can be used instead
struct my_fun
{
    void operator()(const CType& elem) const
    {
        /*...*/
    }
};

/*...*/

using namespace boost::adaptors;

if ( iterate_forward )
    boost::for_each(my_vect, my_fun());
else
    boost::for_each(my_vect | reversed, my_fun());
person Adam Wulkiewicz    schedule 15.04.2014