Untitled :: Boost.OpenMethod

Errors can occur during `initialize`, or during method dispatch, if the method’s registry contains the `runtime_checks` policy. If the registry contains an `error_handler` policy, its `error_handler::error` member function is called with an error object, before terminating the program with a call to `abort`. `default_registry` contains such a policy: `default_error_handler`. It wraps the error object in a variant, and calls a handler via a `std::function`, initialized to a function that prints a short description of the error to `stderr`. The function can be changed, for example, to throw an exception:

    #include <iostream>
    #include <variant>

    #include <boost/openmethod.hpp>
    #include <boost/openmethod/initialize.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::no_overrider>(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` policy 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::no_overrider& 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/initialize.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::no_overrider&) {
                std::cout << "not implemented\n";
            }
        }

        return 0;
    }

    spin
    not implemented
    spin

Stock policy `throw_error_handler` does this for all the error 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

Edit this Page