问题
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 int
s, 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