Reputation:
In my daily work, I usually write my code like this:
int ret = 0;
ret = func1();
if(ret != 0) {
return ret;
}
ret = func2();
if(ret != 0) {
return ret;
}
But this means I need to complete a lot of "if(ret!=0){return ret;}",Is there a more C++ elegant implementation to complete the function jump? By the way, we are not allowed to use exception.
Upvotes: 4
Views: 221
Reputation: 4864
Another possibility is to perform a for range
loop over a set of functions:
for (auto& ff: {func1, func2, func3}) {
Output:
in func1
in func2
in func3
3
Code:
#include <iostream>
int func1() {
std::cout << "in func1\n";
return 0;
}
int func2() {
std::cout << "in func2\n";
return 0;
}
int func3() {
std::cout << "in func3\n";
return 3;
}
int foo () {
for (auto& ff: {func1, func2, func3}) {
int ret;
if ((ret=ff()) != 0) {
return ret;
}
}
return 0;
}
int main() {
std::cout << foo() << "\n";
}
In a comment, you asked the question on how to make it work with member functions. It seems more tricky, in particular because the compiler has difficulty to guess the proper type of the initializer_list. This is one way to solve it.
#include <iostream>
class Obj {
public:
int func1() {
std::cout << "in func1\n";
return 0;
}
int func2() {
std::cout << "in func2\n";
return 0;
}
int func3() {
std::cout << "in func3\n";
return 3;
}
int foo () {
for (auto ff: {&func1, &func2, &func3}) {
int ret;
if ((ret=(this->*ff)()) != 0) {
return ret;
}
}
return 0;
}
};
int main() {
Obj var;
std::cout << var.foo() << "\n";
}
Upvotes: 2
Reputation: 24758
By using a fold expression and an if
statement with initialization you can write the following variadic function template that takes an arbitrary number of pointers to such functions as non-type template arguments:
template<int(...Funcs)()> // equivalent to template<int(*...Funcs)()>
int overall_func() {
if (int ret; (... || (ret = Funcs())))
return ret;
return 0;
}
This way, you factor out all the calls to those functions, the corresponding return value assignments, and their individual checks. Eventually, it boils down to a single check and a single return
statement:
if (int ret = overall_func<func1, func2, func3>(); ret)
return ret;
This is regardless of the number of functions to call.
Upvotes: 2
Reputation: 1015
#include <iostream>
#include <functional>
struct Status{
int status;
template<typename Func, typename... Args>
Status& invoke(Func&& func, Args&&... args){
if (!status)
status = std::invoke(std::forward<Func>(func), std::forward<Args>(args)...);
return *this;
};
int value() const noexcept{
return status;
}
};
int func1(){
std::cout << "call func 1" << std::endl;
return 0;
}
int func2(int a){
std::cout << "call func 2 with " << a << std::endl;
return a;
}
int func3(float x){
std::cout << "call func 3 with " << x << std::endl;
return 1;
}
int foo(){
std::cout << "call foo" << std::endl;
return Status{}.invoke(func1).invoke(func2, 0).invoke(func3, 0).value();
}
int bar(){
std::cout << "call bar" << std::endl;
return Status{}.invoke(func2, 3).invoke(func1).invoke(func3, 0).value();
}
int main(){
int a;
a = foo();
std::cout << "foo return " << a << std::endl;
a = bar();
std::cout << "bar return " << a << std::endl;
return 0;
}
it shows:
call foo
call func 1
call func 2 with 0
call func 3 with 0
foo return 1
call bar
call func 2 with 3
bar return 3
I don't think it's the best way to do that, but it's elegant enough, in my mind. you can serialize all functions and apply short-circuit evaluation (that's why invoke
is needed). or you can write it as a command style:
int foo(){
return Status{}
.invoke(func1)
.invoke(func2, 0)
.invoke(func3, 3)
.value();
}
by the way, if you want to know more about this, you can refer to Monad in Haskell.
Upvotes: 2
Reputation: 881653
C++, as a descendant of C, has the same short-hand method for assignment and checking together:
int ret;
if ((ret = func1()) != 0) return ret;
if ((ret = func2()) != 0) return ret;
This works because a = something
is itself an expression whose value is a
.
If you wanted to type even less code for each call-and-check, you could opt for a macro, but that's probably overkill (I wouldn't do it myself), but I'll show it just in case you're interested:
#define RNZ(x) if ((ret = x) != 0) return ret
int ret;
RNZ(func1());
RNZ(func2());
Upvotes: 1
Reputation: 118352
The shown code seems to be logically equivalent to:
int ret;
if ((ret=func1()) || (ret=func2()))
return ret;
Tack on as many additional function calls as you wish, in the obvious manner.
Upvotes: 5