mirror of
https://github.com/boostorg/openmethod.git
synced 2026-01-19 04:22:12 +00:00
133 lines
4.9 KiB
C++
133 lines
4.9 KiB
C++
// Copyright (c) 2018-2025 Jean-Louis Leroy
|
|
// Distributed under the Boost Software License, Version 1.0.
|
|
// See accompanying file LICENSE_1_0.txt
|
|
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
#ifndef BOOST_OPENMETHOD_POLICY_VECTORED_ERROR_HPP
|
|
#define BOOST_OPENMETHOD_POLICY_VECTORED_ERROR_HPP
|
|
|
|
#include <boost/openmethod/preamble.hpp>
|
|
|
|
#include <functional>
|
|
#include <variant>
|
|
|
|
namespace boost::openmethod::policies {
|
|
|
|
//! Calls a std::function with the error.
|
|
//!
|
|
//! Wraps the error in a @ref std::variant, and calls a `std::function` with it.
|
|
//! The function object is initialized to a function (@ref default_handler) that
|
|
//! writes a description of the error, using the @ref output policy, if it is
|
|
//! available in the registry.
|
|
//!
|
|
//! This is the error handler used by the default registry. In debug variants,
|
|
//! it writes an error message to `stderr`, then returns. In release variants,
|
|
//! no message is emitted. Any call by the library to the error policy is
|
|
//! immediately followed by a call to @ref abort.
|
|
//!
|
|
//! By default, the library is exception-agnostic: it is exception-safe, but it
|
|
//! does not throw exceptions by itself. The program may replace the default
|
|
//! handler with a function that throws an exception, possibly preventing
|
|
//! program termination. The @ref throw_error_handler policy can also be used to
|
|
//! enable exception throwing on a registry basis.
|
|
|
|
struct default_error_handler : error_handler {
|
|
//! A ErrorHandlerFn metafunction.
|
|
//!
|
|
//! @tparam Registry The registry containing this policy.
|
|
template<class Registry>
|
|
class fn {
|
|
template<typename, typename, typename>
|
|
struct error_variant_aux;
|
|
|
|
template<
|
|
typename T, class... Errors, class Policy, class... MorePolicies>
|
|
struct error_variant_aux<
|
|
T, std::variant<Errors...>, mp11::mp_list<Policy, MorePolicies...>>
|
|
: error_variant_aux<
|
|
void, std::variant<Errors...>,
|
|
mp11::mp_list<MorePolicies...>> {};
|
|
|
|
template<class... Errors, class Policy, class... MorePolicies>
|
|
struct error_variant_aux<
|
|
std::void_t<typename Policy::errors>, std::variant<Errors...>,
|
|
mp11::mp_list<Policy, MorePolicies...>>
|
|
: error_variant_aux<
|
|
void,
|
|
mp11::mp_append<
|
|
std::variant<Errors...>, typename Policy::errors>,
|
|
mp11::mp_list<MorePolicies...>> {};
|
|
|
|
template<class... Errors>
|
|
struct error_variant_aux<
|
|
void, std::variant<Errors...>, mp11::mp_list<>> {
|
|
using type = std::variant<Errors...>;
|
|
};
|
|
|
|
public:
|
|
//! A @ref std::variant containing an instance of a subclass of @ref
|
|
//! openmethod_error.
|
|
using error_variant = typename error_variant_aux<
|
|
void,
|
|
std::variant<
|
|
not_initialized, no_overrider, ambiguous_call, missing_class,
|
|
missing_base, odr_violation, final_error>,
|
|
typename Registry::policy_list>::type;
|
|
|
|
//! The type of the error handler function object.
|
|
using function_type = std::function<void(const error_variant& error)>;
|
|
|
|
//! Calls a function with the error object, wrapped in an @ref
|
|
//! error_variant.
|
|
//!
|
|
//! @tparam Error A subclass of @ref openmethod_error.
|
|
//! @param error The error object.
|
|
template<class Error>
|
|
static auto error(const Error& error) -> void {
|
|
handler(error_variant(error));
|
|
}
|
|
|
|
//! Sets the function to be called to handle errors.
|
|
//!
|
|
//! Sets the error handler function to a new value, and returns the
|
|
//! previous function.
|
|
//!
|
|
//! @param new_handler the new function.
|
|
//! @return The previous function.
|
|
static auto set(function_type new_handler) -> function_type {
|
|
auto prev = handler;
|
|
handler = std::move(new_handler);
|
|
|
|
return prev;
|
|
}
|
|
|
|
//! The default error handler function.
|
|
//!
|
|
//! @param error A variant containing the error.
|
|
//!
|
|
//! If `Registry` contains an @ref output policy, writes a description
|
|
//! of the error; otherwise, does nothing.
|
|
static auto default_handler(const error_variant& error) -> void {
|
|
if constexpr (Registry::has_output) {
|
|
std::visit(
|
|
[](auto&& error) {
|
|
error.template write<Registry>(Registry::output::os);
|
|
},
|
|
error);
|
|
Registry::output::os << "\n";
|
|
}
|
|
}
|
|
|
|
private:
|
|
static function_type handler;
|
|
};
|
|
};
|
|
|
|
template<class Registry>
|
|
typename default_error_handler::fn<Registry>::function_type
|
|
default_error_handler::fn<Registry>::handler = default_handler;
|
|
|
|
} // namespace boost::openmethod::policies
|
|
|
|
#endif
|