2012-05-28 16 views
6

Chcę utworzyć kilka typów wyjątków, które pochodzą od std :: runtime_error i chcę, aby miały typ stringstream. Mam w związku z tym stworzyliśmy klasę wyjątku, który komponuje std::stringstream i wynikającemu z std::runtime_error:Dlaczego nie mogę złapać tego wyjątku?

template<typename T> 
class error_stream : public std::runtime_error 
{ 
public: 
     error_stream() : 
     std::runtime_error(""), ss(std::make_shared<std::basic_stringstream<T>>()) 
     { 
     } 

     ~error_stream() throw() 
     { 
     } 

     template <typename T> 
     error_stream & operator << (const T & t) 
     { 
      *ss << t; 
      return *this; 
     } 

     virtual const char * what() const throw() 
     { 
      get_str(s_, ss->str()); 
      return s_.c_str(); 
     } 

protected: 

    template <typename T> 
    void get_str(std::basic_string<char> & s_, const std::basic_string<T> & str) const 
    { 
     s_ = str; 
    } 

    template<> 
    void get_str(std::basic_string<char> & s_, const std::basic_string<wchar_t> & str) const 
    { 
     std::basic_string<char> ret(str.begin(), str.end()); 
     s_ = ret; 
    } 

protected: 
    std::shared_ptr<std::basic_stringstream<T>> ss; 
    mutable std::basic_string<char> s_; 
}; 

I stworzyliśmy bardziej konkretny typ wyjątku, co z kolei wynika z tego error_stream wyjątek:

template<typename T> 
class w32file_exception : public w32utils::error_stream<T> 
{ 
public: 
    w32file_exception() : error_stream<T>() {} 
}; 

Jednak spotkałem się z czymś, czego tutaj nie rozumiem, ponieważ kiedy rzucam w32file_exception, faktycznie mogę go złapać tylko jako rodzica error_stream. Czy ktoś może zobaczyć, co robię źle?

try 
    { 
     throw w32file_exception<char>() << "test"; 
    } 
    catch (w32file_exception<char> & e) 
    { 
     ASSERT_PASSED; 
    } 
    catch (error_stream<char> & e) 
    { 
     std::cout << e.what() << std::endl; // Why do I end up here? 
    } 
+0

Nie znam twojego przypadku użycia 'operatora <<', więc nie wiem, czy to pomaga - ale chciałem tylko wspomnieć o [Boost.Exception] (http://www.boost.org/ doc/libs/1_49_0/libs/exception/doc/boost-exception.html), a w szczególności [Transportowanie arbitralnych danych do strony catch] (http://www.boost.org/doc/libs/1_49_0/libs) /exception/doc/tutorial_transporting_data.html) –

Odpowiedz

13

Jaka jest dokładnie Twoja wersja throw? Używasz operator<< przed wywołaniem rzut, tak:

throw w32file_exception<T>() << "fooobar"; 

to odpowiedź brzmi, że twoi operator<< Zwraca error_stream i nie w32file_exception a więc rodzaj rzucony wyjątek to error_stream.

Można rozwiązać ten problem w ten sposób:

template<typename T, typename DERIVED> 
    class error_stream : public std::runtime_error 
{ 
public: 
    // ... 
    template <typename U> 
     DERIVED & operator << (const T & t) 
    { 
     *ss << t; 
     return static_cast<DERIVED&>(*this); 
    } 
    // ... 
}; 

Ale wtedy tracisz zdolność do połowu wszelkich error_stream wyjątek, ponieważ jest to nowy typ dla każdego DERIVED typu.

+0

Ahh tak, to wygląda, dzięki! – Benj

+0

Kilka problemów (wypróbowałem to sam, ale pobiłeś mnie do odpowiedzi): 1. catch (error_stream & e) 'potrzebuje dodatkowego parametru (ale może to być spowodowane używaniem DevStudio 2005) i 2. Nie użyłem 'static_cast', ale raczej miałem' virtual D & GetThis() = 0; ', który zwrócił wskaźnik' this' typu pochodnego, zdefiniowany w typie pochodnym jako 'virtual w32file_exception & GetThis() {return * this ; } ' – Skizz

+0

@Skizz 1. tak - nie myślałem o tym - możesz ustawić drugi parametr szablonu na" error_stream ". 2. nie powinien czynić żadnych rzeczywistych różnic. Myślę, że oba rozwiązania działają –

Powiązane problemy