2012-03-18 8 views
7

私はstd :: error_codeを使用しており、(enumクラスを使用して)エラーが定義されています登録されたstd :: error_code、my_error :: check_block == my_error :: validate && my_error :: accept_block == my_error :: validate

私は非常に一般的なエラーがあり、現在はmy_error :: validateと呼ばれていますが、私のライブラリに特定のバージョンを提供したいと考えています。一般的に、人々は:std :: error_codeに関連する特定のエラーを表示するか、エラーメッセージを出力したい場合があります。

// ec.message() says "check_block() failed to do XYZ" 
assert(ec == bc::error::check_block); 

私のような何かを有効にすることができるようにしたい:私が何とかカテゴリや条件を使用することができそうです

if (ec == bc::error::validate) 
{ 
    if (ec == bc::error::check_block) 
     // bc::error::check_block is a more specific case of bc::error::validate 
} 

?新しいエラー列挙を一括して定義することなく、どうすればいいですか?これはライブラリ用ですので、そのライブラリのユーザがbc :: generic_error :: validateとbc :: error :: check_blockを使用する必要があるのは苦痛です。

コードは以下の通りです:

#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 {}; 
} 

そしてTUソースファイル:

#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 

答えて

9

OK、私はブーストから助け:: ASIOとstd :: ERROR_CODEクリエータを持って、自分自身をマスター:クリスKohlhoffを。

ADLを使用しているときには、私の場合はエラー:: error_code_tという修飾語は必要ありません。私は間違った範囲にいます。

#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; 
} 
+2

非常に興味深い! C++ 11でカスタムエラーメッセージを実装する方法についてはあまり例がないので、あなたの答えは非常に貴重なリソースです。私はあなたの質問を少し研究したレコードのために、error_conditionを検証し、それをaccept_block/check_blockなどにマップする必要があることに気付きましたが、方法を理解できませんでした。この場合、最終的には普通のenumがC++ 11 enumクラスよりも優れていることが分かります。名前空間にグローバルな可視性があるからです! –

+0

また、は、このエラーコードパーティショニングビジネスでは、あなたのような中程度に複雑なエラーフレームワークをサポートするように十分にうまく設計されていることがとても涼しいです。私はちょっとシステムをもっとシンプルにするために標準化の間に方法を見つけてほしいと思っています。それは最初の視点でどのように動作するかはまだ分かりません。 –

+1

私はそれがとてもクールなシステムだと思う:)ソースコードはすべて興味のある方はここをクリックしてください:http://gitorious.org/libbitcoin/libbitcoin/trees/master(include/error.hppとsrc/error.cppを参照) – genjix