假设我有这样的伪代码:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}

executeThisFunctionInAnyCase();

函数executeStepX当且仅当前一个成功时执行。 在任何情况下,executeThisFunctionInAnyCase函数都应该在最后被调用。 我在编程方面是一个新手,所以很抱歉提出一个非常基本的问题:有没有一种方法(例如在C/ c++中)以代码易读性为代价,避免长if链产生那种“金字塔式代码”?

我知道如果我们可以跳过executeThisFunctionInAnyCase函数调用,代码可以简化为:

bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;

但是约束是executeThisFunctionInAnyCase函数调用。 break语句可以以某种方式使用吗?


当前回答

假设你不需要单独的条件变量,反转测试并使用else-falthrough作为“ok”路径,将允许你获得更垂直的if/else语句集:

bool failed = false;

// keep going if we don't fail
if (failed = !executeStepA())      {}
else if (failed = !executeStepB()) {}
else if (failed = !executeStepC()) {}
else if (failed = !executeStepD()) {}

runThisFunctionInAnyCase();

省略失败的变量使代码在我看来有点太晦涩了。

在里面声明变量就可以了,不用担心= vs ==。

// keep going if we don't fail
if (bool failA = !executeStepA())      {}
else if (bool failB = !executeStepB()) {}
else if (bool failC = !executeStepC()) {}
else if (bool failD = !executeStepD()) {}
else {
     // success !
}

runThisFunctionInAnyCase();

这很模糊,但很紧凑:

// keep going if we don't fail
if (!executeStepA())      {}
else if (!executeStepB()) {}
else if (!executeStepC()) {}
else if (!executeStepD()) {}
else { /* success */ }

runThisFunctionInAnyCase();

其他回答

假设所需的代码是我目前看到的:

bool conditionA = executeStepA();
if (conditionA){
    bool conditionB = executeStepB();
    if (conditionB){
        bool conditionC = executeStepC();
        if (conditionC){
            ...
        }
    }
}    
executeThisFunctionInAnyCase();

我想说,正确的方法,因为它是最容易阅读和最容易维护的,应该有更少的缩进级别,这是(目前)这个问题的目的。

// Pre-declare the variables for the conditions
bool conditionA = false;
bool conditionB = false;
bool conditionC = false;

// Execute each step only if the pre-conditions are met
conditionA = executeStepA();
if (conditionA)
    conditionB = executeStepB();
if (conditionB)
    conditionC = executeStepC();
if (conditionC) {
    ...
}

// Unconditionally execute the 'cleanup' part.
executeThisFunctionInAnyCase();

这避免了对gotos、异常、dummy while循环或其他困难结构的任何需求,只需继续手头的简单工作。

你也可以这样做:

bool isOk = true;
std::vector<bool (*)(void)> funcs; //vector of function ptr

funcs.push_back(&executeStepA);
funcs.push_back(&executeStepB);
funcs.push_back(&executeStepC);
//...

//this will stop at the first false return
for (auto it = funcs.begin(); it != funcs.end() && isOk; ++it) 
    isOk = (*it)();
if (isOk)
 //doSomeStuff
executeThisFunctionInAnyCase();

通过这种方式,您可以获得最小的线性增长大小,每次调用+1行,并且易于维护。


编辑:(谢谢@Unda)我不太喜欢,因为在我看来你失去了能见度:

bool isOk = true;
auto funcs { //using c++11 initializer_list
    &executeStepA,
    &executeStepB,
    &executeStepC
};

for (auto it = funcs.begin(); it != funcs.end() && isOk; ++it) 
    isOk = (*it)();
if (isOk)
 //doSomeStuff
executeThisFunctionInAnyCase();

As @Jefffrey said, you can use the conditional short-circuit feature in almost every language, I personally dislike conditional statements with more than 2 condition (more than a single && or ||), just a matter of style. This code does the same (and probably would compile the same) and it looks a bit cleaner to me. You don't need curly braces, breaks, returns, functions, lambdas (only c++11), objects, etc. as long as every function in executeStepX() returns a value that can be cast to true if the next statement is to be executed or false otherwise.

if (executeStepA())
 if (executeStepB())
  if (executeStepC())
   //...
    if (executeStepN()); // <-- note the ';'

executeThisFunctionInAnyCase();

任何时候,任何函数返回false,都不会调用下一个函数。

我喜欢@Mayerz的答案,因为你可以在运行时改变要调用的函数(以及它们的顺序)。这有点像观察者模式,其中有一组订阅者(函数、对象等),只要满足给定的任意条件,就会调用和执行这些订阅者。在许多情况下,这可能是一个过度杀戮,所以明智地使用它:)

如果你的代码像你的例子一样简单,并且你的语言支持短路计算,你可以尝试这样做:

StepA() && StepB() && StepC() && StepD();
DoAlways();

如果您将参数传递给函数并返回其他结果,因此您的代码不能以以前的方式编写,那么许多其他答案将更适合解决这个问题。

我认为c++ 23的可选的一元操作会做得很好,尽管函数需要做一些改变。

and_then()方法执行break或调用下一个函数操作,链接该方法允许逐个调用函数,直到其中一个返回false。

举个简单粗暴的例子:

#include <iostream>
#include <optional>
#include <cstdlib>

using namespace std;

optional<bool> func1() {
    cout << "func1\n";

    if (rand() % 2)
        return true;
    else
        return nullopt;
}

optional<bool> func2(optional<bool> v) {
    cout << "func2\n";

    if (rand() % 2)
        return true;
    else
        return nullopt;
}

optional<bool> func3(optional<bool> v) {
    cout << "func3\n";

    if (rand() % 2)
        return true;
    else
        return nullopt;
}

void func4() {
    cout << "func4\n";
}

int main() {
    srand(time(NULL));

    func1()
      .and_then(func2)
      .and_then(func3);

    func4();

    return 0;
}