我想创建一些从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?
}
答案 0 :(得分:13)
throw
到底是什么样的?您是否在调用throw之前使用operator<<
,如下所示:
throw w32file_exception<T>() << "fooobar";
然后答案是,您的operator<<
返回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
类型的新类型。