优雅的方式在没有goto的情况下在C++中执行多个依赖错误检查,而且没有提前返回?

Ada*_*m S -5 c++ error-handling goto

假设我想连续调用四个函数,这些函数在我的某个对象上运行.如果其中任何一个失败,我想返回FAILURE而不调用其他人,我想要返回SUCCESSiff所有这些都成功完成.

通常,我会做这样的事情:

if(function_zero(&myMutableObject) == SUCCESS)
{
    return FAILURE;
}
if(function_one(&myMutableObject) == SUCCESS)
{
    return FAILURE;
}
if(function_two(&myMutableObject) == SUCCESS)
{
    return FAILURE;
}
if(function_three(&myMutableObject) == SUCCESS)
{
    return FAILURE;
}

return SUCCESS;
Run Code Online (Sandbox Code Playgroud)

或者,如果我需要做一些清理:

if(function_zero(&myMutableObject) == SUCCESS)
{
    status = FAILURE;
    goto cleanup;
}
if(function_one(&myMutableObject) == SUCCESS)
{
    status = FAILURE;
    goto cleanup;
}
if(function_two(&myMutableObject) == SUCCESS)
{
    status = FAILURE;
    goto cleanup;
}
if(function_three(&myMutableObject) == SUCCESS)
{
    status = FAILURE;
    goto cleanup;
}

cleanup:
// necessary cleanup here
return status;
Run Code Online (Sandbox Code Playgroud)

但是,我正在进行的项目有一些限制:

  • goto,永远
  • 没有提前退货(每个功能一次退货)
  • 行长限制
  • (编辑)没有例外.
  • (编辑)没有模板.

这导致我这样的事情:

if(function_zero(&myMutableObject) == SUCCESS)
{
    if(function_one(&myMutableObject) == SUCCESS)
    {
        if(function_two(&myMutableObject) == SUCCESS)
        {
            status = function_three(&myMutableObject);
        }
        else
        {
            status = FAILURE;
        }
    }
    else
    {
        status = FAILURE;
    }
}
else
{
    status = FAILURE;
}

return status;
Run Code Online (Sandbox Code Playgroud)

不幸的是,这使我经常违反行长限制.

我的问题是:有没有更简单的方法来写这个?

注意事项和限制:

  • 我必须在这里隐含的代码块中实现这个逻辑.我无法创建新功能,重构或更改整体架构.
  • (编辑)实际上,功能具有非常不同的签名.

Pup*_*ppy 7

使用例外和RAII.这些都是他们发明要解决的问题.例外情况更多的是系统范围的功能,而不是您可以在本地应用的功能.

对于清理块,RAII正是您需要的功能.

对于成功/失败,我们可以使用lambdas和variadics隐式链接它们.

现在我们可以简单地将它们写成列表中的lambda.

status f() {
    struct nested {
        static template<typename F> status_t Check(F f) {
            return f();
        }
        static template<typename F, typename... Chain> status_t Check(F f, Chain... chain) {
            auto status = f();
            return status != failure ? Check(chain...) : status;
        }
    };
    return nested::Check( 
        [] { return function_zero(&myMutableObject); },
        [] { return function_one(&myMutableObject); },
        [] { return function_two(&myMutableObject); },
        [] { return function_three(&myMutableObject); },
    );
}
Run Code Online (Sandbox Code Playgroud)

如果你需要捕获返回值,这会变得有点问题,但由于它似乎总是带有out参数的错误代码,如果你只是声明接收变量f(),那么应该没问题,那么所有未来的lambdas都可以引用它.它也不要求每个函数具有相同的签名或分配各种数据结构.

  • @AdamS我知道你会感到沮丧,但对语言的不完全了解是解雇正确答案的一个奇怪的原因.接受答案_是一种学习方法.(解雇他们是浪费时间和业力.) (9认同)
  • 具有不同签名的功能很好,但严重.你忘了补充说你几乎不能使用每种语言功能?! (8认同)
  • 找到那些设置了这些限制的人并反复打击它们,因为它们完全是愚蠢的.然后找一份新工作.然后发布一个实际详细说明您所有要求的问题,而不仅仅是其中的一些要求.(另外,f()在正文中只有一个return语句.) (3认同)
  • @Jefffrey,我知道这可能令人沮丧,但完全掌握一门语言并不是提问的先决条件.提出问题*是一种学习方法. (2认同)

kbi*_*irk 5

仅当状态当前使用&&运算符设置为SUCCESS时才调用测试.如果设置为FAILURE,&&将立即失败,后续测试将不会执行.

status = SUCCESS

if (status == SUCCESS && function_zero(&myMutableObject) == FAILURE)
{
    status = FAILURE;
}
if (status == SUCCESS && function_one(&myMutableObject) == FAILURE)
{
    status = FAILURE;
}
if (status == SUCCESS && function_two(&myMutableObject) == FAILURE)
{
    status = FAILURE;
}
if (status == SUCCESS && function_three(&myMutableObject) == FAILURE)
{
    status = FAILURE;
}

return status;
Run Code Online (Sandbox Code Playgroud)

正如@Mooing Duck建议的那样,你可以简单地在else if链中完成所有操作:

status = SUCCESS

if (function_zero(&myMutableObject) == FAILURE)
{
    status = FAILURE;
}
else if (function_one(&myMutableObject) == FAILURE)
{
    status = FAILURE;
}
else if (function_two(&myMutableObject) == FAILURE)
{
    status = FAILURE;
}
else if (function_three(&myMutableObject) == FAILURE)
{
    status = FAILURE;
}

return status;
Run Code Online (Sandbox Code Playgroud)