How it works...

In our application, we create a data type that can hold either an expected value or an error code in a type-safe way. C++17 provides a type-safe union class, std::variant, which we are going to use as an underlying data type for our templated class, Expected.

The Expected class encapsulates an std::variant field that can hold one of two data types, either templated type T or std::error_code, which is a standard C++ generalization of error codes:

  std::variant<T, std::error_code> v;

Although it is possible to work with std::variant directly, we expose public methods that make it more convenient. The valid method returns true if the result holds the templated type, otherwise false:

  bool valid() const {
return std::holds_alternative<T>(v);
}

The value and error methods are used to access returned values or error code, respectively:

  const T& value() const {
return std::get<T>(v);
}

const std::error_code& error() const {
return std::get<std::error_code>(v);
}

Once the Expected class is defined, we create an OpenForReading function that uses it. This invokes the open system function and, based on the return value, creates an instance of Expected that holds either a file descriptor or error code:

  if (fd < 0) {
return Expected<int>(std::error_code(errno,
std::system_category()));
}
return Expected<int>(fd);

In the main function, when we call OpenForReading for non-existing files, it is expected to fail. When we run the application, we can see the following output:

Our Expected class allows us to write functions that may return error codes, and do it in a type-safe way. Compile time-type validation helps developers to avoid many issues common to traditional error codes, making our applications more robust and safe.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.192.3