什么是有条件地控制for循环方向的最佳方法

时间:2013-10-25 23:24:43

标签: c++ loops iterator

我的代码中有一个块,其中for循环应该根据条件向前或向后运行。

if (forwards) {
    for (unsigned x = 0; x < something.size(); x++ ) {
        // Lots of code
    }

} else {
    for (unsigned x = something.size()-1 ; x >= 0 ; x-- ) {
        // Lots of code
    }
} 

有没有一种很好的方法来设置它,所以我不会重复两次for循环中的所有代码?

有问题的'东西'是std :: vector&lt;&gt;,所以也许它可能带有迭代器? (我没有使用C ++ 11)

5 个答案:

答案 0 :(得分:7)

将循环值与循环中使用的值分开:

for (unsigned x2 = 0; x2 < something.size(); x2++ ) {
    const int x = forward ? x2 : (something.size()-1) - x2;
    // Lots of code using x
}

答案 1 :(得分:6)

最简单的方法可能是将Lots of code转换为带参数x的函数,并用对该函数的调用替换这两个循环体:

void do_lots_of_stuff(unsigned x) {
  // Lots of code
}

////////

if (forwards) {
  for (unsigned x = 0; x < something.size(); x++ ) {
    do_lots_of_stuff(x);
  }
} else {
  for (unsigned x = something.size()-1 ; x >= 0 ; x-- ) {
    do_lots_of_stuff(x);
  }
}

答案 2 :(得分:3)

或者你可以这样做:

for (unsigned x = (forward ? 0: something.size()); x != (forward ? something.size() :0); forward? x++: x-- ) {
    // Lots of code
}

编译器很可能会优化它并仅评估forward一次,因为它的值在我假设的for循环中没有变化。

答案 3 :(得分:2)

template<typename Cont, typename Func>
Func directional_for_each(Cont c, bool forwards, Func f) {
    return forwards ? for_each(begin(c), end(c), f) : for_each(rbegin(c), rend(c), f);
}

像这样使用:

vector<int> v;
// put stuff in v...
bool forwards = false;
directional_for_each(v, forwards, [](decltype(v[0]) x) {
    // Lots of code using x
});

由于您没有使用C ++ 11,因此必须使用其他地方定义的函数替换包含“使用x的许多代码”的lambda。

答案 4 :(得分:0)

我碰巧碰到了这个问题,并且认为我可以提供一个解决方案,无需有条件地检查每个循环是否向前或向后。

// Could do 0xFFFFFFFFU if unsigned is 32bits.
const unsigned MAX_UINT = 0U - 1U;

// Will need this later.
const bool backwards = !forwards;

// temp is either going to be one or zero.
const unsigned temp = unsigned(forwards);

// By adding it to all ones, if temp is ones the mask is all zeros
// else if temp is zero we get all ones.
const unsigned mask = temp + MAX_UINT;

// Bit shift temp over such that it will push all of the ones after
// the first bit to all zeros if temp is one. This means we will
// either have a one or a negative one if temp is zero.
const int delta = int((temp << 1) + MAX_UINT);

const int size = something.size();

// The mask will be zero if forwards is true therein i will start out
// at zero else the mask will be all ones therein return (size - 1).
for(int i = int((size - 1) & mask);
// This may be a more complicated check, but there is only one conditional branch.
    (forwards && (i < size)) || (backwards (0 <= i));
    i += delta)
{
    // Lots of code
}