如何在不同的for循环之间切换,这样的机制会有什么意义吗?

时间:2013-07-04 10:05:16

标签: c++ c loops for-loop

这更像是一个,我很想知道它是否有意义问题,而不是一个,我有一个真正的问题,我在你的意见中强调。如果存在任何语法错误,我使用伪代码来说明要描述的意图。

我有一个使用for循环的程序。

for (frame_pos = 0; frame_pos < frame_size; frame_pos++) {
 ABC...
}

现在我想添加另一种可能的方法来迭代我的程序。

for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
 ABC...
}

所以我写了一个if语句

if(a == true){
 for (frame_pos = 1; frame_pos <= frame_size; frame_pos++) {
  ABC...
 }
}else{
 for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
  ABC...
 }
}

但不知怎的,我不喜欢它,因为我复制了我的代码。

  ABC...

当然,我可以将所有内容从循环中移动到方法中,并且只调用该方法。但我想知道,如果像

那样的话
switch(a){
case(true):
 for (frame_pos = 1; frame_pos <= frame_size; frame_pos++) {
 break;
default:
 for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
 break; 
}

是可能的,如果可能的话,有用且有意义,因为我会在这里使用它。当然,它不一定必须是switch-case它可能是其他一些机制。但我的目的是从我的角度分割atomic

for( ; ; ) {
...
}

身体并重新组合它。

6 个答案:

答案 0 :(得分:4)

ABC成为一个函数(extract method)并调用它。

答案 1 :(得分:4)

如果你不想在运行期间在两种方法之间切换,你可以在预处理器级别解决这个问题:

#define _USENEXT /* Comment out this line to use the "counter" approach. */

...
for (
#ifdef _USENEXT
  frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext
#else
  frame_pos = 1; frame_pos <= frame_size; frame_pos++
#endif
)
{
  <some code>
}

作为代码中#define _USENEXT的替代方法,我可以在编译时将其指定为选项。对于gcc,这将是-D _USENEXT

答案 2 :(得分:3)

某些语言具有轻松使这些模式可重用的机制。例如,C#会让你写下类似的内容:

IEnumerable<Frame> Frames1() {
   for (frame_pos = 0; frame_pos < frame_size; frame_pos++) {
    yield return framelist[framepos];
   }
}
IEnumerable<Frame> Frames2() {
  for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
    yield return framelist[framepos];
   }
}

然后您可以将这些迭代模式视为与其他任何类似的第一类对象。

foreach(var frame in a? Frames1() : Frames2()) {
   ABC...
}

使用这样的功能,您可以避免实现细节,例如来自C的循环的那些愚蠢的样板低级错误原语。

C ++没有这样的语法特性,但它也有一个类似的重用迭代模式的机制:迭代器。编写迭代器并不像在C#中那样简单,但是:(

但是标准容器已经提供了合适的迭代器。然后,您可以重用标准库中提供的许多现有迭代模式中的任何一种。

std::vector<int> v = ...;
std::set<int> s = ...;
auto are_equal = std::equal(v.begin(), v.end(), s.begin(), s.end());

好的C ++库也会类似地提供合适的迭代器。 (是的,祝你好运;看起来很多人写“C ++库”并不知道C ++)

答案 3 :(得分:2)

如果你真的不想让ABC成为一个函数然后在两个不同的for循环之间切换,你可以改为编写三个函数:

int initFramepos( int a ) 
{ 
    return( a ? 1 : framelist.first );
}

int checkFramepos( int frame_pos, int a )
{
    return( a ? frame_pos < frame_size ? framelist.hasNext );
}

int incrFramepos( int frame_pos, int a )
{
    return( a ? frame_pos+1 ? framelist.getNext );
}

然后你的for循环看起来像这样:

for( frame_pos = initFramepos( a ); checkFramepos( frame_pos, a ); frame_pos = incrFramepos( frame_pos, a ) )
{
     ABC
}

答案 4 :(得分:2)

干净的解决方案(用于C ++代码 - 这对C不起作用)将为您的特定情况编写迭代器类实现。然后,您可以根据迭代器编写客户端代码,并确定迭代的含义与其实现方式无关(您可以随时决定迭代对您的意义,而无需更改客户端代码)。 / p>

如果你这样做并专门化std::beginstd::end,你将能够在std中使用整个迭代器算法库作为奖励:(sortcopyfind/find_iffor_eachall_ofany_iftransformaccumulate是最有用的,在我的头脑中。

关于其他解决方案,请不要使用宏:它会导致脆弱的代码,很多难以看到的警告。根据经验,在C ++中使用宏应该(接近)最后考虑的任何解决方案。

答案 5 :(得分:1)

您在此描述的正是战略模式旨在解决的问题。 基本上,你需要做的是将每个循环作为一个类中的方法,然后将其中一个作为策略。当然,您可以随时在策略之间切换。

它看起来像这样:

 class Strategy {
    virtual void func () = 0;
 };

 class StrategyA : public Strategy {
    virtual void func () {
         for (frame_pos = 0; frame_pos < frame_size; frame_pos++) {
        ABC...
         }
    }
};

class StrategyB : public Strategy {
virtual void func () {
        for (frame_pos = framelist.first; framlist.hasNext; frame_pos = framelist.getNext) {
            //ABC...
        }
    }
};

class StrategyToTake {

private:
Strategy* strategy;

public:
void execute () {strategy->func();}
void setStrategy (Strategy* newStrategy) {this.strategy = newStrategy;}

};