I am using std :: error_code and have a bunch of specific errors (using the enum class) and registered.
I have a very general error, now called my_error :: validate, but want to provide more specific versions in my library. Usually people will want to use:
if (ec == bc::error::validate)
However, sometimes they may want to see a specific error associated with this std :: error_code, or print an error message.
// ec.message() says "check_block() failed to do XYZ" assert(ec == bc::error::check_block);
I want to include something like:
if (ec == bc::error::validate) { if (ec == bc::error::check_block)
It seems I can somehow use categories or conditions? How can I do this without having to identify a whole host of new enumerations of errors? This is for the library, so it would be painful for the user of this library to use bc :: generic_error :: validate and bc :: error :: check_block.
Code below:
#include <system_error> namespace bc { enum class error { // storage errors missing_object = 1, object_already_exists, unspent_output, // transaction_pool errors bad_transaction, // network errors resolve_failed, network_unreachable, address_in_use, listen_failed, accept_failed, bad_stream, channel_stopped, channel_timeout, // validate validate_failed, check_block, accept_block, connect_block }; class error_category_impl : public std::error_category { public: virtual const char* name() const; virtual std::string message(int ev) const; virtual std::error_condition default_error_condition(int ev) const; }; const std::error_category& error_category(); std::error_code make_error_code(error e); std::error_condition make_error_condition(error e); } // bc namespace std { template <> struct is_error_code_enum<libbitcoin::error> : public true_type {}; }
And the source TU file:
#include <bc/error.hpp> namespace bc { const char* error_category_impl::name() const { return "bitcoin"; } std::string error_category_impl::message(int ev) const { error ec = static_cast<error>(ev); switch (ec) { case error::missing_object: return "Object does not exist"; case error::object_already_exists: return "Matching previous object found"; case error::unspent_output: return "Unspent output"; case error::bad_transaction: return "Transaction failed to validate"; case error::resolve_failed: return "Resolving hostname failed"; case error::network_unreachable: return "Unable to reach remote network"; case error::address_in_use: return "Address already in use"; case error::listen_failed: return "Listen incoming connections failed"; case error::accept_failed: return "Accept connection failed"; case error::bad_stream: return "Bad stream"; case error::channel_stopped: return "Channel stopped"; case error::channel_timeout: return "Channel timed out"; default: return "Unknown error"; } } std::error_condition error_category_impl::default_error_condition(int ev) const { error ec = static_cast<error>(ev); switch (ec) { case error::check_block: case error::accept_block: case error::connect_block: //return error::validate_failed; return std::errc::permission_denied; default: return std::error_condition(ev, *this); } } const std::error_category& error_category() { static error_category_impl instance; return instance; } std::error_code make_error_code(error e) { return std::error_code(static_cast<int>(e), error_category()); } std::error_condition make_error_condition(error e) { return std::error_condition(static_cast<int>(e), error_category()); } } // bc