minus.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. /*!
  2. @file
  3. Defines `boost::hana::minus`.
  4. Copyright Louis Dionne 2013-2022
  5. Distributed under the Boost Software License, Version 1.0.
  6. (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_HANA_MINUS_HPP
  9. #define BOOST_HANA_MINUS_HPP
  10. #include <boost/hana/fwd/minus.hpp>
  11. #include <boost/hana/concept/constant.hpp>
  12. #include <boost/hana/concept/group.hpp>
  13. #include <boost/hana/config.hpp>
  14. #include <boost/hana/core/common.hpp>
  15. #include <boost/hana/core/to.hpp>
  16. #include <boost/hana/core/dispatch.hpp>
  17. #include <boost/hana/detail/canonical_constant.hpp>
  18. #include <boost/hana/detail/has_common_embedding.hpp>
  19. #include <boost/hana/fwd/negate.hpp>
  20. #include <boost/hana/plus.hpp>
  21. #include <boost/hana/value.hpp>
  22. #include <type_traits>
  23. namespace boost { namespace hana {
  24. //! @cond
  25. template <typename X, typename Y>
  26. constexpr decltype(auto) minus_t::operator()(X&& x, Y&& y) const {
  27. using T = typename hana::tag_of<X>::type;
  28. using U = typename hana::tag_of<Y>::type;
  29. using Minus = BOOST_HANA_DISPATCH_IF(decltype(minus_impl<T, U>{}),
  30. hana::Group<T>::value &&
  31. hana::Group<U>::value
  32. );
  33. #ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
  34. static_assert(hana::Group<T>::value,
  35. "hana::minus(x, y) requires 'x' to be in a Group");
  36. static_assert(hana::Group<U>::value,
  37. "hana::minus(x, y) requires 'y' to be in a Group");
  38. #endif
  39. return Minus::apply(static_cast<X&&>(x), static_cast<Y&&>(y));
  40. }
  41. //! @endcond
  42. template <typename T, typename U, bool condition>
  43. struct minus_impl<T, U, when<condition>> : default_ {
  44. template <typename ...Args>
  45. static constexpr auto apply(Args&& ...) = delete;
  46. };
  47. template <typename T, bool condition>
  48. struct minus_impl<T, T, when<condition>> : default_ {
  49. template <typename X, typename Y>
  50. static constexpr decltype(auto) apply(X&& x, Y&& y) {
  51. return hana::plus(static_cast<X&&>(x),
  52. hana::negate(static_cast<Y&&>(y)));
  53. }
  54. };
  55. // Cross-type overload
  56. template <typename T, typename U>
  57. struct minus_impl<T, U, when<
  58. detail::has_nontrivial_common_embedding<Group, T, U>::value
  59. >> {
  60. using C = typename common<T, U>::type;
  61. template <typename X, typename Y>
  62. static constexpr decltype(auto) apply(X&& x, Y&& y) {
  63. return hana::minus(hana::to<C>(static_cast<X&&>(x)),
  64. hana::to<C>(static_cast<Y&&>(y)));
  65. }
  66. };
  67. //////////////////////////////////////////////////////////////////////////
  68. // Model for arithmetic data types
  69. //////////////////////////////////////////////////////////////////////////
  70. template <typename T>
  71. struct minus_impl<T, T, when<std::is_arithmetic<T>::value &&
  72. !std::is_same<bool, T>::value>> {
  73. template <typename X, typename Y>
  74. static constexpr decltype(auto) apply(X&& x, Y&& y)
  75. { return static_cast<X&&>(x) - static_cast<Y&&>(y); }
  76. };
  77. //////////////////////////////////////////////////////////////////////////
  78. // Model for Constants over a Group
  79. //////////////////////////////////////////////////////////////////////////
  80. namespace detail {
  81. template <typename C, typename X, typename Y>
  82. struct constant_from_minus {
  83. static constexpr auto value = hana::minus(hana::value<X>(), hana::value<Y>());
  84. using hana_tag = detail::CanonicalConstant<typename C::value_type>;
  85. };
  86. }
  87. template <typename C>
  88. struct minus_impl<C, C, when<
  89. hana::Constant<C>::value &&
  90. Group<typename C::value_type>::value
  91. >> {
  92. template <typename X, typename Y>
  93. static constexpr decltype(auto) apply(X const&, Y const&)
  94. { return hana::to<C>(detail::constant_from_minus<C, X, Y>{}); }
  95. };
  96. }} // end namespace boost::hana
  97. #endif // !BOOST_HANA_MINUS_HPP