如何从单个C++返回语句中返回多个值中的一个?

How to return one out of multiple values from a single C++ return statement?

提问人:Ardent Coder 提问时间:5/5/2020 更新时间:5/5/2020 访问量:217

问:

return a or b or c or d;

该语句返回 或以 C++ 形式返回,我知道其中的原因。truefalse

但是我需要一种解决方法,以便我可以通过该 return 语句(或类似的东西)返回第一个非零就像在 Python 中发生的那样

我不是在寻找条件语句,因为它有时看起来不整洁。

基本上,以下代码可以通过宏或其他方式缩短吗?

int fun(int a, int b, int c, int d)
{
    return a ? a : b ? b : c ? c : d;
}
C++ 算法 函数 返回 布尔逻辑

评论


答:

4赞 Ardent Coder 5/5/2020 #1

可以通过在 return 语句中使用必要的函数来完成该任务。

例如,我没有使用宏,而是使用了一个模板化函数,该函数接受 std::initializer_list 中的参数

template <typename T>
T OR(const std::initializer_list<T>& args)
{
    for (const T& arg : args)
        if (arg)
            return arg;
    return T{};
}

对于给定的问题,它可以按如下方式使用:

return OR({a, b, c, d});

该链接中的问题也可以通过以下方式解决:

return OR({(m + s - 1) % n, n});

请注意,它取决于给定类型的隐式布尔转换。因此,例如,空的 std::string 不是 false。此外,用户定义的类型应具有以符合此解决方法。Toperator bool() const

P.S. 当我试图在问题中提出我在可变参数模板解决方案中的错误时,我自己发现了这个解决方案:P

注意:

请参阅答案,了解在处理更复杂的设计时,这种方式的局限性。

评论

2赞 463035818_is_not_an_ai 5/5/2020
哦,你是OP;)
2赞 Jarod42 5/5/2020
initializer_list似乎更好的 IMO,无论如何,方法都需要返回一个唯一类型 (?)。std::common_type
2赞 463035818_is_not_an_ai 5/5/2020
还要注意的是,一旦你写了一个函数,你就失去了短路的能力。
1赞 463035818_is_not_an_ai 5/5/2020
假设您不使用 S 而是使用 S 调用,那么必须调用这两个函数,因此可以调用。如果你写,那么在万一返回非零的情况下,另一个不会被调用,这就是短途ORintOR({ some_function(),some_other_function()})ORint temp = some_function(); if (temp) return temp; temp = some_other_function(); if (temp) return temp;some_function
1赞 463035818_is_not_an_ai 5/5/2020
我对你的例子没有区别,但它是反对使用这种函数的论据,也许是你在 C++ 中(但在 python 中)没有找到这样的东西的部分原因fun
4赞 463035818_is_not_an_ai 5/5/2020 #2

我会这样写这个函数:

int fun(int a, int b, int c, int d) {
    if (a) return a;
    else if (b) return b;
    else if (c) return c;
    return d;
}

它干净而简短。我可以到此为止,但让我们探讨一下可以做些什么......

有一种算法几乎可以做你想做的事。在此答案中对解决方案略有修改:

#include <algorithm>
#include <initializer_list>

template <typename T>
T first_non_zero_or_zero(const std::initializer_list<T>& args)
{
    auto it = std::find_if_not(args.begin(),args.end(),[](auto v){ return v==0;});    
    return (it != args.end()) ? *it : 0;
}

对布尔表达式使用函数的缺点是不能短引用。如果通过以下方式调用函数:

auto x = first_non_zero_or_zero( { foo(), expensive_function() });

然后必须被调用,无论返回什么。恢复短路能力的方法是传递可调用对象,即expensive_functionfoo

template <typename F>
auto first_non_zero_or_zero(F f){ return f();}

template <typename First,typename...F>
auto first_non_zero_or_zero(First f,F... others){    
    if (auto temp = f()) return temp;
    return first_non_zero_or_zero(others...);
}

int foo(){ return 0;}
int expensive_function(){ return 42;}

int main()
{
    std::cout << first_non_zero_or_zero(foo,expensive_function);
    return 0;
}

但是,当使用简单的 s 调用时,这将使调用变得不必要冗长,因为您需要将它们包装在可调用对象中:int

int fun(int a,int b,int c) {
    first_non_zero( [](){ return a;},
                    [](){ return b;},
                    [](){ return c;})
}

结论:不要让事情变得过于复杂。函数应该做一件事。你要做的一件事是返回 4 个整数中的第一个非零,而 a 是完成此操作的最简单方法。funif-else

评论

0赞 Ardent Coder 5/5/2020
我的主要目标不是围绕着,那只是一个最小的可重复的例子。我想要的是一种通用的单行方法来模仿 Python 的行为:p但我喜欢这个答案中涵盖的深层概念。fun
1赞 463035818_is_not_an_ai 5/5/2020
@ArdentCoder正如我之前所说,C++不是 Python。通过比较两种语言可以学到很多东西,并尝试看看在一种语言中可以做的事情是否也可以在另一种语言中完成,但通常一种语言中的惯用语言在另一种语言中可能是废话。此外,单行并不总是最易读的。无论如何,我在探索这个问题时玩得很开心,但恕我直言,结论与其他结论一样重要
0赞 Ardent Coder 5/5/2020
哈哈,我也是,这么简单的问题可以让我们探索很多东西,真是令人着迷;)
0赞 Ardent Coder 5/9/2020
你在线吗?我有一个疑问