Есть библиотека (с исходниками), в которой сообщения об ошибках выдаются вот так:
#define LOG(level) std::cerr << #level ": "
bool someFunction()
{
if (error)
{
LOG(ERROR) << "message";
return false;
}
return true;
}
Хочется с минимальными усилиями написать обертку, которая будет кидать исключение с описанием произошедшего:
void someFunctionWrapper()
{
if (!someFunction())
throw std::runtime_error("тут надо как-то узнать сообщение об ошибке")
}
Я думаю сделать как-то так:
class ErrStream
{
boost::thread_ptr<std::ostringstream> err;
public:
void beforeCall() { if (!err) err.reset(new std::ostringstream); }
void afterCall()
{
std::string s = err->str();
if (!s.empty())
{
err.reset();
throw std::runtime_error(s);
}
}
template<class T>
ErrStream& operator<<(const T&v) { *err << v; return *this; }
static ErrStream& get() { static ErrStream err; return err; }
};
struct ErrGuard
{
ErrGuard() { ErrStream::get().beforeCall(); }
~ErrGuard() { ErrStream::get().afterCall(); } // да, деструктор кидает исключения. Однако сама библиотека исключения не кидает
};
#define LOG(level) ErrStream::get() << #level ": "
void someFunctionWrapper()
{
ErrGuard g;
someFunction();
}
Какие тут могут быть грабли? Может можно сделать проще?
Вариант — кидать исключение внутри макроса LOG не годится — библиотека во многих местах явно зовет delete.