1

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

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

身体并重新组合它。

4

6 回答 6

4

制作ABC一个函数(提取方法)并调用它。

于 2013-07-04T10:08:19.310 回答
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作为我的示例中代码中的ing的替代方法_USENEXT,可以在编译时将其指定为选项。对于 gcc,这将是-D _USENEXT.

于 2013-07-04T10:11:16.593 回答
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++)

于 2013-07-04T10:18:04.233 回答
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
}
于 2013-07-04T10:21:01.130 回答
2

干净的解决方案(对于 C++ 代码- 这对 C 不起作用)将是为您的特定情况编写一个迭代器类实现。然后,您可以根据迭代器编写您的客户端代码,并决定什么迭代意味着独立于它的实现方式(您将能够在任何时候决定迭代对您意味着什么,而根本不需要更改客户端代码)。

如果您这样做并专门化std::beginand std::end,您将能够使用 std 中的整个迭代器算法库作为奖励:(sort, copy, find/find_if, for_each, all_of, any_if, transformandaccumulate是最有用的,我想不到)。

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

于 2013-07-04T11:05:31.007 回答
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;}

};

.

于 2013-07-04T10:47:20.693 回答