首页 > 解决方案 > 优雅地尝试以特定方式执行各种功能

问题描述

我试图按顺序执行各种函数 n 次,只有在前一个函数没有返回 false (错误)的情况下才会继续前进,否则我会重置并重新开始。

一个序列的例子是:

  1. 打开模块 : module.power(true), 3 次尝试
  2. 等待信号 : module.signal(), 10 次尝试
  3. 发送消息 : module.sendSMS('test'), 3 次尝试
  4. 关闭模块 : module.power(false), 1 次尝试

这些操作中的每一个都以相同的方式完成,只是更改了 DEBUG 文本和启动函数:

DEBUG_PRINT("Powering ON");  // This line changes
uint8_t attempts = 0;
uint8_t max_attempts = 3;  // max_attempts changes
while(!module.power(true) && attempts < max_attempts){  // This line changes
  attempts++;
  DEBUG_PRINT(".");
  if(attempts == max_attempts) {
    DEBUG_PRINTLN(" - Failed.");
    soft_reset();  // Start all over again
  }
  delay(100);
}
DEBUG_PRINTLN(" - Success");
wdt_reset(); // Reset watchdog timer, ready for next action

有没有一种优雅的方式可以将这个过程放在一个函数中,我可以调用以这种特定方式执行所需的函数,例如:

void try_this_action(description, function, n_attempts)

这将使上面的动作 1-4 像:

try_this_action("Powering ON", module.power(true), 3);
try_this_action("Waiting for signal", module.signal(), 10);
try_this_action("Sending SMS", module.sendSMS('test'), 3);
try_this_action("Powering OFF", module.power(false), 1);

我遇到的一个困难是被调用的函数有不同的语法(有些带参数,有些不带......)。除了在我需要的任何地方复制/粘贴代码块之外,还有更优雅的可模块化方式吗?

标签: c++arduino

解决方案


我遇到的一个困难是被调用的函数有不同的语法(有些带参数,有些不带......)。

这确实是一个问题。与它一起,您可能会在同一函数的实际函数参数中发生变化。

除了在我需要的任何地方复制/粘贴代码块之外,还有更优雅的可模块化方式吗?

我认为您可以制作一个可变参数函数,该函数使用函数的特定知识进行调度,以处理不同的函数签名和实际参数。不过,我怀疑我是否会认为结果更优雅。

我倾向于通过宏来完成这项工作,而不是:

// desc:     a descriptive string, evaluated once
// action:   an expression to (re)try until it evaluates to true in boolean context
// attempts: the maximum number of times the action will be evaluated, itself evaluated once
#define try_this_action(desc, action, attempts) do { \
    int _attempts = (attempts);                      \
    DEBUG_PRINT(desc);                               \
    while(_attempts && !(action)) {                  \
        _attempts -= 1;                              \
        DEBUG_PRINT(".");                            \
        delay(100);                                  \
    }                                                \
    if (_attempts) {                                 \
        DEBUG_PRINTLN(" - Success");                 \
    } else {                                         \
        DEBUG_PRINTLN(" - Failed.");                 \
        soft_reset();                                \
    }                                                \
    wdt_reset();                                     \
} while (0)

用法就像您描述的那样:

try_this_action("Powering ON", module.power(true), 3);

等等.. 虽然效果就好像你确实在每个位置插入了每个动作的代码,但使用这样的宏会产生更容易阅读的代码,并且在词法上不是重复的。因此,例如,如果您需要更改尝试操作的步骤,您可以通过修改宏一劳永逸地完成。


推荐阅读