【问题标题】:c++ Same checking on function return over and over againc ++一遍又一遍地检查函数返回
【发布时间】:2024-01-17 12:54:02
【问题描述】:
int cmd_x() {
    int result;
    result = func1(x, y);
    if (result != 0) {
        return result;
    }

    result = func2();
    if (result != 0) {
        return result;
    }

    result = func1(x, y, z, w);
    if (result != 0) {
        return result;
    }

    ...

    return result;
}

cmd_x 以瀑布方式执行多个功能。每个函数都返回result。我应该确保result 成功才能继续下一步。

这个if 条件在代码中多次出现,这使得理解和阅读变得更加困难。

有没有办法彻底摆脱这种情况?

我正在考虑创建一个函数指针数组并对其进行循环以仅检查一次代码,但由于函数参数的数量不同,我无法实现它。

【问题讨论】:

  • 您可以使用异常(如果这是一个异常事件)并让cmd_x 的调用站点捕获异常
  • 异常很慢。 cmd_x 是否假设计算事物或检查是否发生了非常错误的事情并且程序应该停止?
  • 也许做一个链式api?就像state.transform1().transform2().transform3() 在每个转换中,如果结果为 0,则不执行任何操作。这仍然不能合并所有 if 语句,但它会将 if 语句放入每个转换中。
  • @Rzu cmd_x 在硬件上执行一些命令,如果一个命令失败,我应该中断下一个命令的执行。您的想法最好从 cmd_x 读取以了解正在执行哪些命令。
  • @NathanOliver 我无法调用cmd_x 检查异常的站点,如果它可以在cmd_x 内部完成,我很想看到它的实现。

标签: c++ coding-style


【解决方案1】:

这看起来很像错误处理(“如果我得到一个非零错误代码,停止并返回该代码”)。如果这些错误是异常的,那么在func1 等中使用异常处理可能是有意义的——如果它们会返回非零错误代码,它们会抛出一个期望。然后可以在最合适的位置(可能是多个函数调用)捕获此异常,从而避免您在调用层次结构中一直进行错误处理。

如果错误不是异常的,事情就会变得复杂。如果您可以将所有函数调用打包到某种容器中,则可以迭代该容器。这里的问题是找到函数的通用类型。
或者,可变参数模板可以完成这项工作:

template<class Func, class... OtherFuncs>
int cmd_x_impl(Func&& func, OtherFuncs&&... otherFuncs)
{
   int result = func();
   if (result != 0)
     return result;
   cmd_x_impl(otherFuncs...);
}

template<class Func>
int cmd_x_impl(Func&& func)
{
    return func();
}

int cmd_x() {
    return cmd_x_impl(
        [&]() { return func1(x, y); },
        [&]() { return func2(); },
        [&]() { return func1(x, y, z, w); }
    );
}

https://godbolt.org/g/wihtCj

这会将您的所有函数调用包装在 lambda 中,然后使用可变参数模板递归来一个接一个地调用它们,只要每个结果为 0。与另一个答案中显示的 std::function 方法相比的优势在于,这是很多编译器更容易看穿和优化。使用上也更简洁,复用性也更强。

【讨论】:

    【解决方案2】:

    我可以想出以下方法来稍微简化你的代码。

    选项 1:使用条件表达式

    int cmd_x()
    {
        int x = 0, y = 0, z = 0, w = 0;
    
        int result = func1(x, y);
    
        result = (result != 0) ? result : func2();
    
        result = (result != 0) ? result : func1(x, y, z, w);
    
        // ...
    
        result = (result != 0) ? result : funcN();
    
        return result;
    }
    

    选项 2:使用 std::vectorstd::functions

    int cmd_x()
    {
        int x = 0, y = 0, z = 0, w = 0;
        std::vector<std::function<int()>> functionList =
        {
            // Let the lambda functions capture what they need 
            [x, y]() -> int { return func1(x, y); },
            [] () -> int { return func2(); },
            [x, y, z, w] () -> int { return func1(x, y, z, w); },
            [] () -> int { return funcN(); }
        };
    
        for ( auto fn : functionList )
        {
            int result = fn();
            if ( result != 0 )
            {
                return result;
            }
        }
    
        return 0;
    }
    

    选项 3:使用辅助函数和std::function

    这是一种混合方法,在辅助函数中使用条件表达式,在主函数中使用 lambda 函数。

    int cmd_helper(int r, std::function<int()> fn)
    {
       return ( r != 0 ) ? r : fn();
    }
    
    int cmd_x()
    {
        int x = 0, y = 0, z = 0, w = 0;
    
        int result = 0;
    
        result = cmd_helper(result, [x, y]() -> int { return func1(x, y); });
    
        result = cmd_helper(result, [] () -> int { return func2(); });
    
        result = cmd_helper(result, [x, y, z, w] () -> int { return func1(x, y, z, w); });
    
        result = cmd_helper(result, [] () -> int { return funcN(); });
    
        return result;
    }
    

    【讨论】: