如何在循环中只运行一次代码而不使用外部标志?

14

我想在循环内检查一个条件,并在第一次满足条件时执行一段代码块。之后,循环可能会重复,但是应该忽略该代码块。有没有这样的模式?当然可以在循环外声明一个标志变量。但我感兴趣的是完全在循环内部解决问题的方法。

这个例子不是我想要的。有没有一种方法可以摆脱循环外部的定义?

bool flag = true;
for (;;) {
    if (someCondition() && flag) {
        // code that runs only once
        flag = false;
    }        
    // code that runs every time
}

7
为什么不将那段代码移出循环? - sharptooth
我不认为使用标志有任何问题。如果我不想这样做,我只会将它移到其他地方。 - Rapptz
假设“跳出循环”不是您要寻找的内容,那么您如何确定什么内容只需执行一次,并在何时执行? - Mats Petersson
1
@MatsPetersson 我希望只在第一次到达代码块时执行给定的代码块。这可能是循环的第一次迭代,但由于其他条件语句,它也可能是稍后的某个时间点。 - danijar
@MatsPetersson 我正在寻找一种摆脱手动定义标志的方法。要么有内联解决方案(C++中没有内联类,对吧?)。要么我需要一个外部管理器来处理。 - danijar
显示剩余8条评论
6个回答

14

这个方法有点hacky,但是根据您所说的应用程序主循环,我认为它在一个只被调用一次的函数中,因此以下内容应该有效:

struct RunOnce {
  template <typename T>
  RunOnce(T &&f) { f(); }
};

:::

while(true)
{
  :::

  static RunOnce a([]() { your_code });

  :::

  static RunOnce b([]() { more_once_only_code });

  :::
}

这正是我正在寻找的。我们能否在执行 lambda 后在构造函数中销毁实例? - danijar
1
@danijar 不,它具有静态存储期限,因此它将在程序关闭时被销毁。问题是为什么你需要这样做。请注意,lambda表达式不会存储在结构体中,只是执行并被遗忘(即被销毁)。结构体实例本身可能只占用1-4个字节,具体取决于您的编译器而没有任何操作。 - Angew is no longer proud of SO
好吧,这样做就不会感觉像是hacky了。 - danijar

12

对于一个更简化版本的Mobius答案:

while(true)
{
  // some code that executes every time
  for(static bool first = true;first;first=false)
  {
    // some code that executes only once
  }
  // some more code that executes every time.
}

你也可以使用 ++ 来操作布尔值,但是这种方法已经被弃用了。


3
一种可能更加简洁的写法是使用变量,具体如下:
while(true){
   static uint64_t c;
   // some code that executes every time
   if(c++ == 0){
      // some code that executes only once
   }
   // some more code that executes every time.
 }

static关键字允许你在循环内部声明变量,这样看起来更加清晰。如果你的代码每次执行都会产生可测试的变化,那么你可以摆脱这个变量,像这样编写代码:

while(true){
   // some code that executes every time
   if(STATE_YOUR_LOOP_CHANGES == INITIAL_STATE){
      // some code that executes only once
   }
   // some more code that executes every time.
 }

4
c会不断递增,直到超出 short 的范围,然后重新循环回0,是这样吗? - Clark Kent
是的,我包括计数器变量,因为在一般情况下它可能更有用。 - Mobius
@Mobius 我认为不是这样,因为只有一次的代码块不太可能在每次迭代中都被执行到。所以计数器变量不会代表循环次数。 - danijar
@danijar 我在想if语句应该在每次迭代中执行,所以c应该在每次迭代中递增。我有什么地方不对吗? - Mobius
1
如果你担心会出现环绕的问题,为什么不直接使用64位整数?在我的笔记本上进行快速测试表明,它需要大约1000年的时间才能计数到1.8e19(64位整数的最大值)。 - SirGuy
显示剩余5条评论

0
#include <iostream>
using namespace std;

int main()
{
    int fav_num = 0;

    while (true)
    {
    if ( fav_num == 0)
    {
        cout <<"This will only run if variable fav_number is = 0!"<<endl;
    }
    cout <<"Please give me your favorite number."<<endl;
    cout <<"Enter Here: ";
    cin >>fav_num;
    cout <<"Now the value of variable fav_num is equal to "<<fav_num<<" and not 0 so, the if statement above won't run again."<<endl;
    }
    
    return 0;
}

输出

This will only run if variable fav_number is = 0!

Please give me your favorite number.

Enter Here: 1

Now the value of variable fav_num is equal to 1 and not 0 so, the "if statement" above won't run again.

1
你的回答可以通过提供更多支持信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人可以确认你的答案是正确的。您可以在帮助中心中找到有关如何编写良好答案的更多信息。 - Community

-1
如果你知道你只想运行这个循环一次,为什么不在循环中使用break作为最后一个语句呢?

-2
1    while(true)
2    {
3        if(someCondition())
4        {
5            // code that runs only once
6            // ...
7          // Should change the value so that this condition must return false from next execution.
8        }        
9    
10        // code that runs every time
11        // ...
12    }

如果你期望在没有任何外部标志的情况下得到代码结果,那么你需要修改条件语句的最后一个语句中的值。(代码片段的第7行)

请阅读问题下面的注释。例如,如果玩家等级超过给定数字,他应该获得一次奖励。我不能降低玩家等级,只是为了不重复颁发奖励。while(1){ if(level > 7){ once([=]{ award(); }); } } - danijar
请再次阅读问题下面的评论,因为第一个问题是在不使用标志的情况下如何实现,然后才考虑其他选择。 - Meg
无论标志是布尔变量还是在条件函数内的另一个标志,在while循环之前,这有什么关系吗? - danijar
这里我没有提到标志,因为我不想创建任何新的变量或标志(可重用性概念)。通过使用条件值,我们可以操作相同的内容。请验证我的代码。 - Meg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接