// This program illustrates how one can use error codes effectively: // define a number of error code ranges from different sub-systems // (FlightsErrc, Flights2Errc, SeatsErrc), // define a default error condition for plugging all those codes // into the system of errors (SubsystemError), // and a number of 'queries' on the error codes // (FailureSource, Severity) // FILE: flights.h # include <system_error> enum class FlightsErrc { // no 0 NonexistentLocations = 10, // requested airport doesn't exist DatesInThePast, // booking flight for yesterday InvertedDates, // returning before departure NoFlightsFound = 20, // did not find any combination ProtocolViolation = 30, // e.g., bad XML ConnectionError, // could not connect to server ResourceError, // service run short of resources Timeout, // did not respond in time }; namespace std { template <> struct is_error_code_enum<FlightsErrc> : true_type {}; } std::error_code make_error_code(FlightsErrc); // FILE: flights2.h # include <system_error> enum class Flights2Errc { ZeroFlightsFound = 11, InvalidRequestFormat = 12, CouldNotConnect = 13, DatabaseError = 14, NotEnoughMemory = 15, InternalError = 16, NoSuchAirport = 17, JourneyInThePast = 18, DatesNotMonotonic = 19, }; namespace std { template <> struct is_error_code_enum<Flights2Errc> : true_type {}; } std::error_code make_error_code(Flights2Errc); // FILE: seats.h enum class SeatsErrc { // no 0 InvalidRequest = 1, // e.g., bad XML CouldNotConnect, // could not connect to server InternalError, // service run short of resources NoResponse, // did not respond in time NonexistentClass, // requested class does not exist NoSeatAvailable, // all seats booked }; namespace std { template <> struct is_error_code_enum<SeatsErrc> : true_type {}; } std::error_code make_error_code(SeatsErrc); // FILE submodule_error.h # include <system_error> enum class SubsystemError { // no 0 InputBadAirport = 1, InputPastDate, InputBadDateRange, InputBadClass, NoFlightFound, NoSeatFound, SubsysProtocolErr, SubsysInternal, SubsysResource, SubsysConfig, SubsysTimeout, }; namespace std { template <> struct is_error_condition_enum<SubsystemError> : true_type {}; } std::error_condition make_error_condition(SubsystemError e); // FILE queries.h # include <system_error> enum class FailureSource { // no 0 BadUserInput = 1, SystemError = 2, NoSolution = 3, }; namespace std { template <> struct is_error_condition_enum<FailureSource> : true_type {}; } std::error_condition make_error_condition(FailureSource e); enum class Severity { // no 0 Bug = 1, Config, Resource, Normal, }; namespace std { template <> struct is_error_condition_enum<Severity> : true_type {}; } std::error_condition make_error_condition(Severity e); // FILE: main.cpp // # include "flights.h" // # include "seats.h" # include <cassert> # include <iostream> int main () { std::error_code ec = FlightsErrc::NoFlightsFound; assert (ec == SubsystemError::NoFlightFound); assert (ec != SubsystemError::InputBadClass); assert (ec == FailureSource::NoSolution); assert (ec != FailureSource::BadUserInput); assert (ec == Severity::Normal); assert (ec != Severity::Bug); ec = SeatsErrc::NonexistentClass; assert (ec != SubsystemError::NoFlightFound); assert (ec == SubsystemError::InputBadClass); assert (ec != FailureSource::NoSolution); assert (ec == FailureSource::BadUserInput); assert (ec == Severity::Normal); assert (ec != Severity::Config); std::cout << ec << std::endl; // the following illustrates how you insert // raw int values into error_code system: int ret_value = 20; // it was returned from Flights std::error_code ec2 = static_cast<FlightsErrc>(ret_value); std::cout << ec2 << std::endl; } // FILE: flights.cpp // # include "flights.h" namespace { // anonymous namespace struct FlightsErrCategory : std::error_category { const char* name() const noexcept override; std::string message(int ev) const override; std::error_condition default_error_condition(int ev) const noexcept override; }; const char* FlightsErrCategory::name() const noexcept { return "flights"; } std::string FlightsErrCategory::message(int ev) const { switch (static_cast<FlightsErrc>(ev)) { case FlightsErrc::NonexistentLocations: return "nonexistent airport name in request"; case FlightsErrc::DatesInThePast: return "request for a date from the past"; case FlightsErrc::InvertedDates: return "requested flight return date before departure date"; case FlightsErrc::NoFlightsFound: return "no filight combination found"; case FlightsErrc::ProtocolViolation: return "received malformed request"; case FlightsErrc::ConnectionError: return "could not connect to server"; case FlightsErrc::ResourceError: return "insufficient resources"; case FlightsErrc::Timeout: return "processing timed out"; default: return "(unrecognized error)"; } } std::error_condition FlightsErrCategory::default_error_condition(int ev) const noexcept { switch (static_cast<FlightsErrc>(ev)) { case FlightsErrc::NonexistentLocations: return SubsystemError::InputBadAirport; case FlightsErrc::DatesInThePast: return SubsystemError::InputPastDate; case FlightsErrc::InvertedDates: return SubsystemError::InputBadDateRange; case FlightsErrc::NoFlightsFound: return SubsystemError::NoFlightFound; case FlightsErrc::ProtocolViolation: return SubsystemError::SubsysProtocolErr; case FlightsErrc::ConnectionError: return SubsystemError::SubsysConfig; case FlightsErrc::ResourceError: return SubsystemError::SubsysResource; case FlightsErrc::Timeout: return SubsystemError::SubsysTimeout; default: assert(false); return {}; } } const FlightsErrCategory theFlightsErrCategory {}; } // anonymous namespace std::error_code make_error_code(FlightsErrc e) { return {static_cast<int>(e), theFlightsErrCategory}; } // FILE: flights2.cpp // # include "flights2.h" namespace { // anonymous namespace struct Flights2ErrCategory : std::error_category { const char* name() const noexcept override; std::string message(int ev) const override; std::error_condition default_error_condition(int ev) const noexcept override; }; const char* Flights2ErrCategory::name() const noexcept { return "flights2"; } std::string Flights2ErrCategory::message(int ev) const { switch (static_cast<Flights2Errc>(ev)) { // return name for each enum default: return "(unrecognized error)"; } } std::error_condition Flights2ErrCategory::default_error_condition(int ev) const noexcept { switch (static_cast<Flights2Errc>(ev)) { case Flights2Errc::ZeroFlightsFound: return SubsystemError::NoFlightFound; case Flights2Errc::InvalidRequestFormat: return SubsystemError::SubsysProtocolErr; case Flights2Errc::CouldNotConnect: return SubsystemError::SubsysConfig; case Flights2Errc::DatabaseError: return SubsystemError::SubsysInternal; case Flights2Errc::NotEnoughMemory: return SubsystemError::SubsysResource; case Flights2Errc::InternalError: return SubsystemError::SubsysInternal; case Flights2Errc::NoSuchAirport: return SubsystemError::InputBadAirport; case Flights2Errc::JourneyInThePast: return SubsystemError::InputPastDate; case Flights2Errc::DatesNotMonotonic: return SubsystemError::InputBadDateRange; default: assert(false); return {}; } } const Flights2ErrCategory theFlights2ErrCategory {}; } // anonymous namespace std::error_code make_error_code(Flights2Errc e) { return {static_cast<int>(e), theFlights2ErrCategory}; } // FILE: seats.cpp // # include "seats.h" namespace { // anonymous namespace struct SeatsErrCategory : std::error_category { const char* name() const noexcept override; std::string message(int ev) const override; std::error_condition default_error_condition(int ev) const noexcept override; }; const char* SeatsErrCategory::name() const noexcept { return "seats"; } std::string SeatsErrCategory::message(int ev) const { switch (static_cast<SeatsErrc>(ev)) { case SeatsErrc::InvalidRequest: return "received malformed request"; case SeatsErrc::CouldNotConnect: return "could not connect to server"; case SeatsErrc::InternalError: return "insufficient resources"; case SeatsErrc::NoResponse: return "processing timed out"; case SeatsErrc::NonexistentClass: return "requested class does not exist"; case SeatsErrc::NoSeatAvailable: return "all seats booked"; default: return "(unrecognized error)"; } } std::error_condition SeatsErrCategory::default_error_condition(int ev) const noexcept { switch (static_cast<SeatsErrc>(ev)) { case SeatsErrc::InvalidRequest: return SubsystemError::SubsysProtocolErr; case SeatsErrc::CouldNotConnect: return SubsystemError::SubsysConfig; case SeatsErrc::InternalError: return SubsystemError::SubsysInternal; case SeatsErrc::NoResponse: return SubsystemError::SubsysTimeout; case SeatsErrc::NonexistentClass: return SubsystemError::InputBadClass; case SeatsErrc::NoSeatAvailable: return SubsystemError::NoSeatFound; default: assert(false); return {}; } } const SeatsErrCategory theSeatsErrCategory {}; } // anonymous namespace std::error_code make_error_code(SeatsErrc e) { return {static_cast<int>(e), theSeatsErrCategory}; } // FILE: queries.cpp // # include "queries.h" namespace { class SubsystemErrorCategory : public std::error_category { public: const char* name() const noexcept override; std::string message(int ev) const override; }; const char* SubsystemErrorCategory::name() const noexcept { return "submodule-error"; } std::string SubsystemErrorCategory::message(int ev) const { switch (static_cast<SubsystemError>(ev)) { default: return "(uncharted)"; } } const SubsystemErrorCategory theSubsystemErrorCategory {}; } std::error_condition make_error_condition(SubsystemError e) { return {static_cast<int>(e), theSubsystemErrorCategory}; } // ----------------- namespace { class FailureSourceCategory : public std::error_category { public: const char* name() const noexcept override; std::string message(int ev) const override; bool equivalent( const std::error_code& code, int condition) const noexcept override; }; const char* FailureSourceCategory::name() const noexcept { return "failure-source"; } std::string FailureSourceCategory::message(int ev) const { switch (static_cast<FailureSource>(ev)) { case FailureSource::BadUserInput: return "invalid user request"; case FailureSource::SystemError: return "internal error"; case FailureSource::NoSolution: return "no solution found for specified request"; default: return "(unrecognized condition)"; } } bool FailureSourceCategory::equivalent( const std::error_code& ec, int cond) const noexcept { switch (static_cast<FailureSource>(cond)) { case FailureSource::BadUserInput: return ec == SubsystemError::InputBadAirport || ec == SubsystemError::InputPastDate || ec == SubsystemError::InputBadDateRange || ec == SubsystemError::InputBadClass; case FailureSource::SystemError: return ec == SubsystemError::SubsysProtocolErr || ec == SubsystemError::SubsysInternal || ec == SubsystemError::SubsysResource || ec == SubsystemError::SubsysConfig || ec == SubsystemError::SubsysTimeout; case FailureSource::NoSolution: return ec == SubsystemError::NoFlightFound || ec == SubsystemError::NoSeatFound; default: return false; } } const FailureSourceCategory theFailureSourceCategory {}; } // anonymous namespace std::error_condition make_error_condition(FailureSource e) { return {static_cast<int>(e), theFailureSourceCategory}; } // -------------- namespace { class SeverityCategory : public std::error_category { public: const char* name() const noexcept override; std::string message(int ev) const override; bool equivalent( const std::error_code& code, int condition) const noexcept override; }; const char* SeverityCategory::name() const noexcept { return "severity"; } std::string SeverityCategory::message(int ev) const { switch (static_cast<Severity>(ev)) { case Severity::Bug: return "failure is a programmer bug"; case Severity::Config: return "failure is a configuration error"; case Severity::Resource: return "failure is caused by resource shortage"; case Severity::Normal: return "failure requires no attention"; default: return "(unrecognized condition)"; } } bool SeverityCategory::equivalent( const std::error_code& ec, int cond) const noexcept { switch (static_cast<Severity>(cond)) { case Severity::Bug: return ec == SubsystemError::SubsysProtocolErr || ec == SubsystemError::SubsysInternal; case Severity::Config: return ec == SubsystemError::SubsysConfig; case Severity::Resource: return ec == SubsystemError::SubsysResource || ec == SubsystemError::SubsysTimeout; case Severity::Normal: return ec == SubsystemError::InputBadAirport || ec == SubsystemError::InputPastDate || ec == SubsystemError::InputBadDateRange || ec == SubsystemError::InputBadClass || ec == SubsystemError::NoFlightFound || ec == SubsystemError::NoSeatFound; default: return false; } } const SeverityCategory theSeverityCategory {}; } // anonymous namespace std::error_condition make_error_condition(Severity e) { return {static_cast<int>(e), theSeverityCategory}; }