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