Std :: error_code, my_error :: check_block == my_error :: validate && my_error :: accept_block == my_error :: validate

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) // bc::error::check_block is a more specific case of bc::error::validate } 

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 
+7
source share
1 answer

OK I got help from the creator boost :: asio and std :: error_code and the master himself: Chris Kohlhoff.

When using ADL, a good rule is that it does not need any qualifier (error :: error_code_t in my case), and I ended up in the wrong volume.

 #include <iostream> #include <system_error> namespace libbitcoin { namespace error { // Specific errors enum error_code_t { // 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 check_block, accept_block, connect_block }; // error_condition enum error_condition_t { // validate validate_failed = 1 }; std::error_code make_error_code(error_code_t e); std::error_condition make_error_condition(error_condition_t e); } 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(); } // libbitcoin namespace std { template <> struct is_error_code_enum<libbitcoin::error::error_code_t> : public true_type {}; template <> struct is_error_condition_enum<libbitcoin::error::error_condition_t> : public true_type {}; } // ------------------------------------------------------------------- namespace libbitcoin { namespace error { std::error_code make_error_code(error_code_t e) { return std::error_code(static_cast<int>(e), error_category()); } std::error_condition make_error_condition(error_condition_t e) { return std::error_condition(static_cast<int>(e), error_category()); } } 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 (ev) { 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"; case error::check_block: return "Checkblk"; default: return "Unknown error"; } } std::error_condition error_category_impl::default_error_condition(int ev) const { //error ec = static_cast<error>(ev); switch (ev) { case error::check_block: case error::accept_block: case error::connect_block: return std::error_condition(error::validate_failed, *this); default: return std::error_condition(ev, *this); } } const std::error_category& error_category() { static error_category_impl instance; return instance; } } // libbitcoin using namespace libbitcoin; #include <assert.h> int main() { std::error_code ec = error::check_block; assert(ec == error::validate_failed); assert(ec == error::check_block); std::cout << ec.message() << std::endl; //ec = error::missing_object; return 0; } 
+9
source

All Articles