В типах исключений нет ничего особенного. Они такие же типы, как и другие, просто они предназначены для исключения. Учтите, что вы можете throw
объекты любого типа, а не только типы, унаследованные от std::exception
.
Причина, по которой вы не нашли примеров, возможно, в том, что более типично наследовать от std::runtime_error
, а затем просто вызывать конструктор, когда вы хотите его выбросить. Что-то вроде строки
struct my_runtime_error : std::runtime_error {
{
template<typename ... Ts>
my_runtime_error(const char * frmt, Ts ... args);
};
Или, как предлагается в комментарии, напишите функцию, которая возвращает void
и вместо throw
s само исключение:
template<typename ... Ts>
[[ noreturn ]] void throw_error(const char * frmt, Ts ... args)
{
const int n = std::snprintf(nullptr, 0, frmt, args...);
std::vector<char> buff(n + 1);
std::snprintf(&buff[0], n + 1, frmt, args...);
throw std::runtime_error(std::string(buff.data()));
}
, чтобы быть используется как
void some_process(int x)
{
if (x < 0)
throw_error(errmsg(x));
}
Тем не менее, у этого недостатка является то, что он всегда бросает одну и ту же функцию вместо того места, где на самом деле возникает проблема, и если бы мне пришлось выбирать между этим и вашим, я бы go для вашего решение.
PS: обратите внимание, что std::exception
и его потомки предназначены для наследования в отличие от большинства других типов в стандартной библиотеке. std::exception
имеет виртуальный деструктор.