我想创建一些从std :: runtime_error派生的异常类型,我希望它们具有stringstream类型功能.因此,我创建了一个异常类,它组成了一个std :: stringstream,它派生自std :: runtime_error:
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_; };
我创建了一个更具体的异常类型,该类型又从这个error_stream异常中派生出来:
template<typename T> class w32file_exception : public w32utils::error_stream<T> { public: w32file_exception() : error_stream<T>() {} };
但是,我遇到了一些我不明白的事情,因为当我抛出一个w32file_exception时,我实际上只能捕获它,因为它是父的error_stream.谁能看到我做错了什么?
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? }
解决方法
你的投掷到底是什么样的?您使用的操作符<<在调用throw之前,像这样:
throw w32file_exception<T>() << "fooobar";
然后答案是,您的操作符<<返回error_stream而没有w32file_exception,因此抛出异常的类型是error_stream. 你可以这样解决这个问题:
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); } // ... };
但是你失去了捕获每个error_stream异常的能力,因为它是每个DERIVED类型的新类型.