2012-05-28 16 views
6

Voglio creare un numero di tipi di eccezioni che derivano da std :: runtime_error e voglio che abbiano funzionalità di tipo stringstream. Ho quindi creato un classe di eccezione che compone un std::stringstream e che deriva da std::runtime_error:Perché non riesco a rilevare questa eccezione?

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_; 
}; 

E ho creato un tipo di eccezione più specifica che a sua volta deriva da questo error_stream eccezione:

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

Tuttavia, ho riscontrato qualcosa che non capisco qui, perché quando lancio un w32file_exception in realtà riesco a prenderlo solo perché è il genitore error_stream. Qualcuno può vedere cosa sto facendo male?

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

Non conosco il tuo caso d'uso dell''operatore << 'quindi non so se questo aiuta - ma volevo solo menzionare [Boost.Exception] (http://www.boost.org/ doc/libs/1_49_0/libs/exception/doc/boost-exception.html) e in particolare il [Trasporto di dati arbitrari al sito Catch] (http://www.boost.org/doc/libs/1_49_0/libs /exception/doc/tutorial_transporting_data.html) –

risposta

13

Che aspetto ha esattamente il tuo throw? Si sta utilizzando il vostro operator<< prima di chiamare tiro, in questo modo:

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

allora la risposta è, che i operator<< restituisce un error_stream e non w32file_exception e così il tipo di eccezione generata è error_stream.

Si potrebbe risolvere il problema in questo modo:

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); 
    } 
    // ... 
}; 

Ma poi si perde la capacità di cogliere ogni error_stream eccezione perché è un nuovo tipo per ogni tipo DERIVED.

+0

Ahh sì, sembra così, grazie! – Benj

+0

Un paio di problemi (l'ho provato io stesso ma mi hai risposto alla risposta): 1. 'catch (error_stream & e)' ha bisogno di un parametro aggiuntivo (ma potrebbe essere perché stavo usando DevStudio 2005) e 2. Non avevo 'static_cast', ma piuttosto un' virtuale D & GetThis() = 0; 'che restituiva il puntatore' this' del tipo derivato, definito nel tipo derivato 'virtuale w32file_exception e GetThis() {return * this ; } ' – Skizz

+0

@Skizz 1. sì - non ci ho pensato - potresti impostare il parametro del secondo template su error_stream'. 2. non dovrebbe fare alcuna differenza reale. Penso che entrambe le soluzioni funzionino –

Problemi correlati