Error Handling
When an error is encountered, the program is terminated by a call to abort
. If
the policy contains an error_handler
facet, it provides an error
member
function (or overloaded functions) to be called with an object identifying the
error. The release
and debug
policies implement the error facet with
default_error_handler
, which wraps the error object in a variant, and calls a
handler via a std::function
. By default, it prints a description of the error
to stderr
in the debug
policy, and does nothing in the release
policy. The
handler can be set with set_error_handler
:
#include <iostream>
#include <variant>
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
using boost::openmethod::virtual_ptr;
struct Animal {
virtual ~Animal() = default;
};
struct Cat : Animal {};
struct Dog : Animal {};
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
BOOST_OPENMETHOD(trick, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD_OVERRIDE(
trick, (std::ostream & os, virtual_ptr<Dog> /*dog*/), void) {
os << "spin\n";
}
auto main() -> int {
namespace bom = boost::openmethod;
bom::initialize();
bom::default_registry::error_handler::set([](const auto& error) {
if (std::holds_alternative<bom::not_implemented_error>(error)) {
throw std::runtime_error("not implemented");
}
});
Cat felix;
Dog hector, snoopy;
std::vector<Animal*> animals = {&hector, &felix, &snoopy};
for (auto animal : animals) {
try {
trick(std::cout, *animal);
} catch (std::runtime_error& error) {
std::cerr << error.what() << "\n";
}
}
return 0;
}
Output:
spin
not implemented
spin
We can also replace the error_handler
facet with our own. For example:
#include <iostream>
#include <boost/openmethod/default_registry.hpp>
struct Animal {
virtual ~Animal() = default;
};
struct Cat : Animal {};
struct Dog : Animal {};
namespace bom = boost::openmethod;
struct throw_if_not_implemented : bom::policies::error_handler {
template<class Registry>
struct fn {
static auto error(const bom::openmethod_error&) -> void {
}
static auto error(const bom::not_implemented_error& err) -> void {
throw err;
}
};
};
struct custom_registry : bom::default_registry::with<throw_if_not_implemented> {
};
#define BOOST_OPENMETHOD_DEFAULT_REGISTRY custom_registry
#include <boost/openmethod.hpp>
#include <boost/openmethod/compiler.hpp>
using boost::openmethod::virtual_ptr;
BOOST_OPENMETHOD_CLASSES(Animal, Cat, Dog);
BOOST_OPENMETHOD(trick, (std::ostream&, virtual_ptr<Animal>), void);
BOOST_OPENMETHOD_OVERRIDE(
trick, (std::ostream & os, virtual_ptr<Dog> /*dog*/), void) {
os << "spin\n";
}
auto main() -> int {
bom::initialize();
Cat felix;
Dog hector, snoopy;
std::vector<Animal*> animals = {&hector, &felix, &snoopy};
for (auto animal : animals) {
try {
trick(std::cout, *animal);
} catch (bom::not_implemented_error&) {
std::cout << "not implemented\n";
}
}
return 0;
}
spin
not implemented
spin
Stock facet throw_error_handler
does this for all the exception types:
namespace boost::openmethod::policies {
struct throw_error_handler : error_handler {
template<class Error>
[[noreturn]] static auto error(const Error& error) -> void {
throw error;
}
};
} // namespace boost::openmethod::policies