result<T, EC>

Outcome 2.0 namespace

It is recommended that you refer to entities from this Outcome 2.0 via the following namespace alias:

namespace outcome = OUTCOME_V2_NAMESPACE;
View this code on Github

As patches and modifications are applied to this library, namespaces get permuted in order not to break any backward compatibility. At some point namespace outcome::v2 will be defined, and this will be the prefered namespace. Until then OUTCOME_V2_NAMESPACE denotes the most recently updated version, getting closer to outcome::v2.

Creating result<>

We will define a function that converts an std::string to an int. This function can fail for a number of reasons; if it does we want to communicate the failure reason.

outcome::result<int> convert(const std::string& str) noexcept;
View this code on Github

Class template result<T, EC> has two template parameters. The first (T) represents the type of the object returned from the function upon success; the second (EC) is the type of object containing information about the reason for failure when the function fails. A result<T, EC> object either stores a T or an EC at any given moment, and is therefore conceptually similar to variant<T, EC>. EC is defaulted to std::error_code. If both T and EC are trivially copyable, result<T, EC> is also trivially copyable.

Now, we will define an enumeration describing different failure situations during conversion.

enum class ConversionErrc
  EmptyString = 1, // 0 is never an error
  IllegalChar = 2,
  TooLong     = 3,

// all boilerplate necessary to plug ConversionErrc
// into std::error_code framework
View this code on Github

Assume we have plugged it into std::error_code framework, as described in this section.

One notable effect of such plugging is that ConversionErrc is now convertible to std::error_code. Now we can implement function convert as follows:

outcome::result<int> convert(const std::string& str) noexcept
  if (str.empty())
    return ConversionErrc::EmptyString;
  if (!std::all_of(str.begin(), str.end(), ::isdigit))
    return ConversionErrc::IllegalChar;
  if (str.length() > 9)
    return ConversionErrc::TooLong;
  return atoi(str.c_str());
View this code on Github

result<T, EC> is convertible from any T2 convertible to T as well as any EC2 convertible to EC, provided that there is no constructability possible in either direction between T and EC. If there is, all implicit conversion is disabled, and you will need to use one of the tagged constructors:

outcome::result<int> r {outcome::in_place_type<std::error_code>, ConversionErrc::EmptyString};
outcome::result<int> s {outcome::in_place_type<int>, 1};
View this code on Github

Or use helper factory functions:

outcome::result<int> r = outcome::failure(ConversionErrc::EmptyString); 
outcome::result<int> s = outcome::success(1);
View this code on Github