Введение:
Дано:
struct X : std::runtime_error {
using std::runtime_error::runtime_error;
};
Когда мы вызываем std::throw_with_nested(X("foo"))
, то, что на самом деле выбрано, не является X
. Это какой-то тип, который выводится как из X
, так и std::nested_exception
.
поэтому следующее утверждение не будет выполнено:
const std::type_info *a = nullptr, *b = nullptr;
try
{
throw X("1");
}
catch(X& x) {
a = std::addressof(typeid(x));
try {
std::throw_with_nested(X("2"));
}
catch(X& x) {
b = std::addressof(typeid(x));
}
}
assert(std::string(a->name()) == std::string(b->name()));
Я хотел бы сделать вывод, что эти два исключения связаны между собой.
Первая попытка:
std::type_index
deduce_exception_type(const std::exception* pe)
{
if (auto pnested = dynamic_cast<const std::nested_exception*>(pe))
{
try {
std::rethrow_exception(pnested->nested_ptr());
}
catch(const std::exception& e)
{
return deduce_exception_type(std::addressof(e));
}
}
else {
return typeid(*pe);
}
}
Это не работает, потому что std::nested_exception::nested_ptr()
возвращает указатель на следующее исключение по строке, а не на интерфейс X
текущего исключения.
Я ищу (переносимые) идеи и решения, которые позволяют мне восстанавливать typeid (X) из "исключения с неизвестным именем", созданного стандартной библиотекой во время std::rethrow_exception
.
С++ 14 и С++ 1z в порядке.
Почему?
Поскольку я хочу иметь возможность развернуть полную иерархию исключений и передать ее через сеанс rpc, заполните имена типов исключений.
В идеале я не хочу писать блок catch, содержащий все типы исключений в системе, которые должны быть слабо упорядочены по глубине вывода.
Еще один пример ожидаемой функциональности (и иллюстрация, почему мой подход не работает):
const std::type_info *b = nullptr;
try
{
throw std::runtime_error("1");
}
catch(std::exception&) {
try {
std::throw_with_nested(X("2"));
}
catch(X& x) {
// PROBLEM HERE <<== X& catches a std::_1::__nested<X>, which
// is derived from X and std::nested_exception
b = std::addressof(typeid(x));
}
}
assert(std::string(typeid(X).name()) == std::string(b->name()));