Open sdebionne opened 3 years ago
Does anyone have a suggestion on how to implement something like this?
First of all, let's recap try-catch-block:
try
{
f();
}
catch (const std::runtime_error& e)
{
log(e.what); // this executes if f() throws std::runtime_error (same type rule) -- here, we do have a what() function
}
catch (const std::exception& e)
{
log(e.what); // this executes if f() throws std::exception (base class rule) -- here, we do have a what() function
}
catch (...)
{
log("catch_all"); // this executes if f() throws int or any other non-exception type -- here, we do NOT have a what() function
}
with this in common
#include "sml.hpp"
#include <cassert>
#include <iostream>
#include <stdexcept>
namespace sml = boost::sml;
namespace {
struct exception_handling {
auto operator()() const {
using namespace sml;
constexpr auto on_exception = [](const auto& evt) {
if (std::is_same_v<std::remove_cvref_t<decltype(evt)>, std::runtime_error>) std::cout << "std::runtime_error: " << evt.what() << std::endl;
else std::cout << evt.what() << std::endl;
};
constexpr auto on_exception_catch_all = [](const auto& evt) {
std::cout << "catch_all" << std::endl;
};
return make_transition_table(
*("idle"_s) + "event1"_e / [] {
//throw std::logic_error{"ouch2"};
//throw std::exception{};
throw std::runtime_error{"ouch"};
}
, *("exceptions handling"_s) + exception<_> / on_exception_catch_all = "fault"_s
, "exceptions handling"_s + exception<std::runtime_error> / on_exception = "fault"_s
, "exceptions handling"_s + exception<std::exception> / on_exception = "fault"_s
);
}
};
} // namespace
int main() {
using namespace sml;
sm<exception_handling> sm;
sm.process_event("event1"_e());
}
In state "exceptions handling" we have to catch all specializations of std::exception on its own, because else the specializations will be casted to std::exception and we no more information about the type.
See Compiler Explorer Example: https://godbolt.org/z/vved46rah
Thanks for looking into this!
Right, we don't have access directly to the exception in a catch all handler, but calling std::current_exception()
is an option:
catch (...)
{
std::exception_ptr p = std::current_exception();
}
How about passing an std::exception_ptr
to the subsequent action of exception<_>
? Or call std::current_exception()
in the on_exception_catch_all
action?
constexpr auto on_exception_catch_all = [](const auto& evt) {
std::exception_ptr p = std::current_exception();
std::cout <<(p ? p.__cxa_exception_type()->name() : "null") << std::endl;
};
This last option seems to fit the bill for me, but I am not sure it would work with the defer_queue
policy.
For generic
exception<_>
events, it would be useful to inject the event/exception in the subsequent action. AFAIU, it works for typed exception event such asexception<std::runtime_error>
only.Here is a godbolt that shows the "issue" and a repro: