Drise
Drise

Reputation: 4388

Return error value if an error occurs, otherwise, continue with function

Is there any better (more readable and / or with less duplicated code) way to write this in C++?

int func()
{
  int error = foo(); // can return true/false
  if (error != 0) // if an error is returned from foo(), pass it up to the caller of func()
    return error;

  // otherwise, proceed
  error = bar(); // can return true/false
  if (error != 0)
    return error;

  return error; // all calls succeeded, return 0.
}

Upvotes: 1

Views: 1561

Answers (5)

YSC
YSC

Reputation: 40070

If you tend to use this kind of construction often, I'd advise you to define a monad to hide the repetitive behaviour. A simple implementation would go like this.

Implementation

template<typename Return, Return True>
class Monad
{
    Return _result;

public:
    Monad() : _result(True) {}

public:
    template<typename Function, typename... Args>
    Monad&
    call(Function f, Args ...args)
    {
        if (_result == True) {
            _result = f(args...);
        }
        return *this;
    }

    Return result() { return _result; }
};

Usage

bool f()      { std::cout << __PRETTY_FUNCTION__ << "\n"; return true; }
bool g(int n) { std::cout << __PRETTY_FUNCTION__ << "\n"; return n == 42; }
bool h()      { std::cout << __PRETTY_FUNCTION__ << "\n"; return true; }

int main()
{
    Monad<bool, true> m;
    const bool result = m.call(f)
                         .call(g, 56)
                         .call(h)
                         .result();
    std::cout << std::boolalpha << result << "\n";
}

In this case, only f() and g(56) are called (h() is not); result() returns false.

demo

Upvotes: 0

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385144

Yes:

void func()
{
   foo();
   bar();
}

where an exception is thrown up to the caller(s) by either function, if something unexpected occurs.

Error codes are a C-ism.

Upvotes: 1

Peter
Peter

Reputation: 36597

If you only want an indication of true (non-zero) or false (zero) returned, rather than the actual value returned by your called functions

 int func()
 {
      return foo() || bar();
 }

This will return 1 if either foo() or bar() return non-zero, with short circuiting so bar() will not be called if foo() returns non-zero. In this case, consider returning bool rather than int.

If foo() or bar() can return a range of non-zero values (e.g. indicating different error conditions) and you need to preserve those

 int func()
 {
     int error = foo();
     if (!error) error = bar();
     return error;
 }

Upvotes: 4

You want outcome<T>.

https://ned14.github.io/outcome/

But you are going to introduce bigger compile times for the sake of saving a few keystrokes though.

Upvotes: -1

Quentin
Quentin

Reputation: 63124

Your version looks nice enough. The only thing I'd avoid is reusing the same variable, but instead use one separate variable per error and scope it tightly:

int func()
{
  if (int const error = foo())
    return error;

  if (int const error = bar())
    return error;

  return 0;
}

Upvotes: 3

Related Questions