如何在不同的for循环之间切换,这样的机制是否有意义

How to switch between diffrent for loops, and would such a mechanism make any sense?

本文关键字:有意义 是否 机制 之间 循环 for      更新时间:2023-10-16

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

我有一个使用 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( ; ; ) {
...
}

身体并重新组合它。

ABC 做一个函数(提取方法(并调用它。

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

#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.

某些语言具有轻松使此类模式可重用的机制。例如,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++(

如果你真的不想让 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
}

干净的解决方案(对于C++代码 - 这不适用于 C(是为您的特定情况编写迭代器类实现。然后,您可以根据迭代器编写客户端代码,并决定迭代的含义,而与它的实现方式无关(您将能够随时决定迭代对您意味着什么,而无需更改客户端代码(。

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

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

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

它将看起来像这样:

 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;}
};

.