try_cast.hpp 1.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
  1. // Copyright 2019 Hans Dembinski
  2. //
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // (See accompanying file LICENSE_1_0.txt
  5. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_HISTOGRAM_DETAIL_TRY_CAST_HPP
  7. #define BOOST_HISTOGRAM_DETAIL_TRY_CAST_HPP
  8. #include <boost/config.hpp>
  9. #include <boost/core/demangle.hpp>
  10. #include <boost/histogram/detail/type_name.hpp>
  11. #include <boost/mp11/integral.hpp>
  12. #include <boost/throw_exception.hpp>
  13. #include <stdexcept>
  14. #include <string>
  15. #include <type_traits>
  16. namespace boost {
  17. namespace histogram {
  18. namespace detail {
  19. template <class T, class E, class U>
  20. BOOST_NORETURN T try_cast_impl(mp11::mp_int<0>, U&&) {
  21. BOOST_THROW_EXCEPTION(E("cannot cast " + type_name<T>() + " to " + type_name<U>()));
  22. }
  23. template <class T, class E, class U>
  24. T try_cast_impl(mp11::mp_int<1>, U&& u) noexcept {
  25. return static_cast<T>(u);
  26. }
  27. template <class T, class E, class U>
  28. decltype(auto) try_cast_impl(mp11::mp_int<2>, U&& u) noexcept {
  29. return std::forward<U>(u);
  30. }
  31. // cast fails at runtime with exception E instead of compile-time, T must be a value
  32. template <class T, class E, class U>
  33. decltype(auto) try_cast(U&& u) noexcept(std::is_convertible<U, T>::value) {
  34. return try_cast_impl<T, E>(mp11::mp_int<(std::is_convertible<U, T>::value +
  35. std::is_same<T, std::decay_t<U>>::value)>{},
  36. std::forward<U>(u));
  37. }
  38. } // namespace detail
  39. } // namespace histogram
  40. } // namespace boost
  41. #endif