假设我有这样的伪代码:
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语句可以以某种方式使用吗?
一个简单的解决方案是使用一个条件布尔变量,同一个变量可以重复使用,以检查顺序执行的所有步骤的结果:
bool cond = executeStepA();
if(cond) cond = executeStepB();
if(cond) cond = executeStepC();
if(cond) cond = executeStepD();
executeThisFunctionInAnyCase();
并不是说在此之前没有必要这样做:bool cond = true;... 然后后跟if(cond) cond = executeStepA();cond变量可以立即赋值给executeStepA()的结果,因此使代码更短,更易于阅读。
另一个更奇特但有趣的方法是这样的(有些人可能认为这是IOCCC的一个很好的候选,但仍然如此):
!executeStepA() ? 0 :
!executeStepB() ? 0 :
!executeStepC() ? 0 :
!executeStepD() ? 0 : 1 ;
executeThisFunctionInAnyCase();
结果是完全相同的,如果我们做什么OP张贴,即:
if(executeStepA()){
if(executeStepB()){
if(executeStepC()){
if(executeStepD()){
}
}
}
}
executeThisFunctionInAnyCase();
为了改进Mathieu的c++ 11答案并避免通过使用std::function而产生的运行时成本,我建议使用以下方法
template<typename functor>
class deferred final
{
public:
template<typename functor2>
explicit deferred(functor2&& f) : f(std::forward<functor2>(f)) {}
~deferred() { this->f(); }
private:
functor f;
};
template<typename functor>
auto defer(functor&& f) -> deferred<typename std::decay<functor>::type>
{
return deferred<typename std::decay<functor>::type>(std::forward<functor>(f));
}
这个简单的模板类将接受任何不需要任何参数就可以调用的函子,并且这样做不需要任何动态内存分配,因此更好地符合c++的抽象目标,没有不必要的开销。附加的函数模板用于简化模板参数推断的使用(类模板参数不可用)
使用的例子:
auto guard = defer(executeThisFunctionInAnyCase);
bool conditionA = executeStepA();
if (!conditionA) return;
bool conditionB = executeStepB();
if (!conditionB) return;
bool conditionC = executeStepC();
if (!conditionC) return;
正如Mathieu的答案,这个解决方案是完全异常安全的,在所有情况下都将调用executeThisFunctionInAnyCase。如果executeThisFunctionInAnyCase本身被抛出,析构函数被隐式地标记为noexcept,因此将发出对std::terminate的调用,而不是在堆栈展开期间引发异常。
这看起来像一个状态机,这很方便,因为您可以使用状态模式轻松实现它。
在Java中,它看起来像这样:
interface StepState{
public StepState performStep();
}
实现如下所示:
class StepA implements StepState{
public StepState performStep()
{
performAction();
if(condition) return new StepB()
else return null;
}
}
等等。然后你可以将大if条件替换为:
Step toDo = new StepA();
while(toDo != null)
toDo = toDo.performStep();
executeThisFunctionInAnyCase();