default_error_handler.hpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. // Copyright (c) 2018-2025 Jean-Louis Leroy
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // See accompanying file LICENSE_1_0.txt
  4. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_OPENMETHOD_POLICY_VECTORED_ERROR_HPP
  6. #define BOOST_OPENMETHOD_POLICY_VECTORED_ERROR_HPP
  7. #include <boost/openmethod/preamble.hpp>
  8. #include <functional>
  9. #include <variant>
  10. namespace boost::openmethod::policies {
  11. //! Calls a std::function with the error.
  12. //!
  13. //! Wraps the error in a @ref std::variant, and calls a `std::function` with it.
  14. //! The function object is initialized to a function (@ref default_handler) that
  15. //! writes a description of the error, using the @ref output policy, if it is
  16. //! available in the registry.
  17. //!
  18. //! This is the error handler used by the default registry. In debug variants,
  19. //! it writes an error message to `stderr`, then returns. In release variants,
  20. //! no message is emitted. Any call by the library to the error policy is
  21. //! immediately followed by a call to @ref abort.
  22. //!
  23. //! By default, the library is exception-agnostic: it is exception-safe, but it
  24. //! does not throw exceptions by itself. The program may replace the default
  25. //! handler with a function that throws an exception, possibly preventing
  26. //! program termination. The @ref throw_error_handler policy can also be used to
  27. //! enable exception throwing on a registry basis.
  28. struct default_error_handler : error_handler {
  29. //! A ErrorHandlerFn metafunction.
  30. //!
  31. //! @tparam Registry The registry containing this policy.
  32. template<class Registry>
  33. class fn {
  34. template<typename, typename, typename>
  35. struct error_variant_aux;
  36. template<
  37. typename T, class... Errors, class Policy, class... MorePolicies>
  38. struct error_variant_aux<
  39. T, std::variant<Errors...>, mp11::mp_list<Policy, MorePolicies...>>
  40. : error_variant_aux<
  41. void, std::variant<Errors...>,
  42. mp11::mp_list<MorePolicies...>> {};
  43. template<class... Errors, class Policy, class... MorePolicies>
  44. struct error_variant_aux<
  45. std::void_t<typename Policy::errors>, std::variant<Errors...>,
  46. mp11::mp_list<Policy, MorePolicies...>>
  47. : error_variant_aux<
  48. void,
  49. mp11::mp_append<
  50. std::variant<Errors...>, typename Policy::errors>,
  51. mp11::mp_list<MorePolicies...>> {};
  52. template<class... Errors>
  53. struct error_variant_aux<
  54. void, std::variant<Errors...>, mp11::mp_list<>> {
  55. using type = std::variant<Errors...>;
  56. };
  57. public:
  58. //! A @ref std::variant containing an instance of a subclass of @ref
  59. //! openmethod_error.
  60. using error_variant = typename error_variant_aux<
  61. void,
  62. std::variant<
  63. not_initialized, no_overrider, ambiguous_call, missing_class,
  64. missing_base, odr_violation, final_error>,
  65. typename Registry::policy_list>::type;
  66. //! The type of the error handler function object.
  67. using function_type = std::function<void(const error_variant& error)>;
  68. //! Calls a function with the error object, wrapped in an @ref
  69. //! error_variant.
  70. //!
  71. //! @tparam Error A subclass of @ref openmethod_error.
  72. //! @param error The error object.
  73. template<class Error>
  74. static auto error(const Error& error) -> void {
  75. handler(error_variant(error));
  76. }
  77. //! Sets the function to be called to handle errors.
  78. //!
  79. //! Sets the error handler function to a new value, and returns the
  80. //! previous function.
  81. //!
  82. //! @param new_handler the new function.
  83. //! @return The previous function.
  84. static auto set(function_type new_handler) -> function_type {
  85. auto prev = handler;
  86. handler = std::move(new_handler);
  87. return prev;
  88. }
  89. //! The default error handler function.
  90. //!
  91. //! @param error A variant containing the error.
  92. //!
  93. //! If `Registry` contains an @ref output policy, writes a description
  94. //! of the error; otherwise, does nothing.
  95. static auto default_handler(const error_variant& error) -> void {
  96. if constexpr (Registry::has_output) {
  97. std::visit(
  98. [](auto&& error) {
  99. error.template write<Registry>(Registry::output::os);
  100. },
  101. error);
  102. Registry::output::os << "\n";
  103. }
  104. }
  105. private:
  106. static function_type handler;
  107. };
  108. };
  109. template<class Registry>
  110. typename default_error_handler::fn<Registry>::function_type
  111. default_error_handler::fn<Registry>::handler = default_handler;
  112. } // namespace boost::openmethod::policies
  113. #endif