2012-03-18 18 views
7

Tôi đang sử dụng std :: error_code và có một loạt lỗi được xác định (sử dụng lớp enum) và đã đăng ký.std :: error_code, my_error :: check_block == my_error :: validate && my_error :: accept_block == my_error :: validate

Tôi có lỗi rất chung chung hiện được gọi là my_error :: xác thực, nhưng muốn cung cấp các phiên bản cụ thể hơn trong thư viện của tôi. Nói chung mọi người sẽ muốn sử dụng:

if (ec == bc::error::validate) 
    // ... 

Tuy nhiên đôi khi họ có thể muốn xem các lỗi cụ thể liên quan với điều đó std :: error_code hoặc in các thông báo lỗi.

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

Tôi muốn để có thể cho phép một cái gì đó như:

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

Có vẻ như tôi bằng cách nào đó có thể sử dụng loại hoặc điều kiện? Làm thế nào tôi có thể làm điều đó mà không cần phải xác định toàn bộ một loạt các enums lỗi mới? Nó cho một thư viện do đó nó sẽ là một nỗi đau cho người dùng của thư viện đó phải sử dụng bc :: generic_error :: validate và bc :: error :: check_block.

Mã là dưới đây:

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

Và TU file nguồn:

#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 

Trả lời

9

OK tôi có sự giúp đỡ từ các boost :: ASIO và std :: error_code người sáng tạo và làm chủ bản thân: Chris Kohlhoff .

Khi sử dụng ADL, nguyên tắc chung là không cần bất kỳ trình phân loại nào (lỗi :: error_code_t trong trường hợp của tôi) và tôi đã sai phạm vi.

#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

Rất thú vị! Hiện tại không có nhiều ví dụ về cách triển khai thông báo lỗi tùy chỉnh trong C++ 11, vì vậy câu trả lời của bạn là một tài nguyên rất có giá trị. Đối với hồ sơ tôi đã nghiên cứu một chút câu hỏi của bạn, nhận ra rằng bạn phải xác nhận một error_condition và bản đồ nó để accept_block/check_block vv nhưng không thể hình dung như thế nào. Nó khá thú vị để thấy rằng cuối cùng trong trường hợp này enum đồng bằng là tốt hơn so với C++ 11 enum lớp chính xác bởi vì họ có khả năng hiển thị toàn cầu trong không gian tên của họ! –

+0

Cũng khá thú vị khi thấy rằng được thiết kế đủ để hỗ trợ một khung lỗi phức tạp vừa phải giống như của bạn, với việc phân đoạn mã lỗi kinh doanh này. Tôi chỉ muốn họ tìm thấy một cách trong quá trình chuẩn hóa để đơn giản hóa hệ thống một chút bằng cách nào đó, nó vẫn thực sự khó để tìm ra cách nó hoạt động ngay từ cái nhìn đầu tiên. –

+1

Vâng, tôi nghĩ rằng đó là một hệ thống khá thú vị :) Mã nguồn có sẵn ở đây cho tất cả các quan tâm: http://gitorious.org/libbitcoin/libbitcoin/trees/master (xem bao gồm/error.hpp và src/error.cpp) – genjix

Các vấn đề liên quan