Я пишу функцию wd_sprintf
, чтобы предоставить API-интерфейс sprintf. Под обложками используется библиотека ускорения.
Если пользователь wd_sprintf
кодирует строку формата, boost::format
выдаст исключение. Я хотел бы, чтобы моя функция перехватывала исключение, переупаковывает его в сообщении, которое идентифицирует wd_sprintf
как локус ошибки и повторяет исключение.
Я не могу понять, что поймать и как извлечь сообщение.
// wd_sprintf(pattern [,args...]):
//
// This creates a temporary boost::format from pattern, and calls
// wd_sprintf_r() to recursively extract and apply arguments.
#include <boost/exception/all.hpp>
class wd_sprintf_exception : std::runtime_error {
public:
wd_sprintf_exception(string const& msg : std::runtime_error(msg) {}
};
template <typename... Params>
string
wd_sprintf (const string &pat, const Params&... parameters) {
try {
boost::format boost_format(pat);
return wd_sprintf_r(boost_format, parameters...);
}
catch (boost::exception e) {
const string what = string("wd_sprintf: ") + string(e.what());
throw wd_sprintf_exception(what);
}
}
Конечно, это получает ошибку компиляции, потому что boost :: exception является абстрактным.
(Я был на нескольких сайтах и страницах, включая тот, чей заголовок был похож, но который был заполнен операторами "<<", вставляющими в вызов функции, конструкциями шаблонов, такими как boost::get_error_info<my_tag_error_info>(e)
, и, как правило, гораздо сложнее, чем я подозреваю, действительно необходимо. Мне просто нужно, чтобы выше работали.)
Вы не можете иметь автоматическую переменную абстрактного типа. Однако вы можете иметь ссылку или указатель на один. Причина этого заключается в том, что компилятор не имеет возможности точно знать, какой производный тип является фактически переменной, поэтому он не знает, сколько места выделяется для него или какой конструктор экземпляра класса использовать.
Когда вы поймаете boost::exception
по значению, как вы это делаете, компилятор должен сделать локальную копию этого в вашем блоке catch; которой у него недостаточно информации!
В вашем конкретном случае лучшим решением является поиск ссылки на исходное исключение.
Что касается catching exceptions из Boost.Format, он генерирует исключения, полученные из boost::io::format_error
, который получен из std::exception
, not boost::exception
. Вы должны поймать boost::io::format_error
.
e.what()
не работает, потому что boost::exception
не имеет what()
)
boost::exception
(и стандартная библиотека C ++) были разработаны таким образом.