Inspecting outcome

Continuing with the previous example, in Layer3 we have function z which again reports failures via exceptions. It will call function h from Layer2_old which returns outcome<int> (which may store an int or a std::error_code or a std::exception_ptr). The goal is to unpack it to either the successful return value int or to throw an appropriate exception: if we are storing an std::exception_ptr, just rethrow it. If we are storing a std::error_code throw it as std::system_error, which is designed to store std::error_code’s:

auto z() -> int // throws on failure
{
  if (outcome::outcome<int> o = old::h())
    return o.value();
  else if (o.has_exception())
    std::rethrow_exception(o.exception());
  else
    throw std::system_error{o.error()};
}
View this code on Github

Function has_exception() checks if it is EP (std::exception_ptr) that is stored, function exception() accesses it. Similarly, function error() accesses the EC (std::error_code) if it is stored. outcome<> also has a function has_failure() to check if either EC or EP is being stored.

It would seem obvious that the above pattern of ‘unpacking’ outcome<> is so common that it ought to be implemented inside function .value(), so function z could be written as:

return old::h().value();

And this is exactly what the aforementioned no-value policy template argument is for, which is described in the next section.