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

假装没事ソ 提交于 2021-01-28 19:25:36

问题


return a or b or c or d;

That statement returns either true or false in C++, and I know the reason for this.

But I need a workaround so that I can return the first non-zero value via that return statement (or something similar) like it happens in Python.

I am not looking for conditional statements as it looks untidy sometimes.

Basically, can the following code be shortened via a macro or something else?

int fun(int a, int b, int c, int d)
{
    return a ? a : b ? b : c ? c : d;
}

回答1:


I would write the function like this:

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;
}

It is clean and short. I could stop here, but lets explore what can be done...

There exists an algorithm that already almost does what you want. A slight modification of the solution in this answer:

#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;
}

The drawback of using a function for boolean expressions is no short-cuirciting. If you call the function via:

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

Then expensive_function must be called, no matter what foo returns. The way to restore the ability to short-circuit is to pass callables instead, that would be

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;
}

However, this will make calls unnecessarily verbose when called with simple ints, as you need to wrap them in a callable:

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

Conclusion: Don't make things more complicated than necessary. Functions should do one thing. The one thing your fun does is to return the first non-zero of 4 integers and a if-else is the most simple way to get that done.




回答2:


The task can be accomplished by using the necessary function in the return statement.

For example, instead of a macro, I used a templated function which accepts the parameters in 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{};
}

It can be used as follows for the given problem:

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

The problem in that link can also be solved in this way:

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

Note that it depends on the implicit boolean conversion of a given type T. So, for example, an empty std::string is not false. Also, a user-defined type should have operator bool() const in order to comply with this workaround.

P.S. While I was trying to ask my mistake in a variadic template solution in the question, I discovered this solution myself :P

Note:

See this answer to know the limitations of this way when working with more complex designs.



来源:https://stackoverflow.com/questions/61609680/how-to-return-one-out-of-multiple-values-from-a-single-c-return-statement

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!