1 /*!
2 @file
3 Defines `boost::hana::detail::CanonicalConstant`.
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_DETAIL_CANONICAL_CONSTANT_HPP
11 #define BOOST_HANA_DETAIL_CANONICAL_CONSTANT_HPP
12 
13 #include <boost/hana/config.hpp>
14 
15 
16 BOOST_HANA_NAMESPACE_BEGIN namespace detail {
17     //! @ingroup group-details
18     //! Tag representing a canonical `Constant`.
19     //!
20     //! This is an implementation detail used to provide many models for
21     //! stuff like `Monoid`, `Group`, etc. To create a `CanonicalConstant`,
22     //! simply create an object with a nested `hana_tag` equal to the proper
23     //! specialization of `CanonicalConstant<T>`, and then also provide a
24     //! `constexpr` static member `::%value` holding the value of the constant.
25     template <typename T>
26     struct CanonicalConstant {
27         using value_type = T;
28     };
29 } BOOST_HANA_NAMESPACE_END
30 
31 
32 #include <boost/hana/concept/constant.hpp>
33 #include <boost/hana/concept/integral_constant.hpp>
34 #include <boost/hana/core/to.hpp>
35 #include <boost/hana/core/when.hpp>
36 
37 #include <type_traits>
38 
39 
40 BOOST_HANA_NAMESPACE_BEGIN
41     //////////////////////////////////////////////////////////////////////////
42     // Constant
43     //////////////////////////////////////////////////////////////////////////
44     template <typename T>
45     struct value_impl<detail::CanonicalConstant<T>> {
46         template <typename X>
applyvalue_impl47         static constexpr decltype(auto) apply()
48         { return X::value; }
49     };
50 
51     namespace detail {
52         template <typename T, typename X>
53         struct canonical_constant {
54             static constexpr auto value = hana::to<T>(hana::value<X>());
55             using hana_tag = detail::CanonicalConstant<T>;
56         };
57     }
58 
59     template <typename T, typename C>
60     struct to_impl<detail::CanonicalConstant<T>, C, when<
61         hana::Constant<C>::value &&
62         is_convertible<typename C::value_type, T>::value
63     >>
64         : embedding<is_embedded<typename C::value_type, T>::value>
65     {
66         template <typename X>
applyto_impl67         static constexpr detail::canonical_constant<T, X> apply(X const&)
68         { return {}; }
69     };
70 
71     //////////////////////////////////////////////////////////////////////////
72     // IntegralConstant (when value_type is integral)
73     //////////////////////////////////////////////////////////////////////////
74     template <typename T>
75     struct IntegralConstant<detail::CanonicalConstant<T>> {
76         static constexpr bool value = std::is_integral<T>::value;
77     };
78 BOOST_HANA_NAMESPACE_END
79 
80 #endif // !BOOST_HANA_DETAIL_CANONICAL_CONSTANT_HPP
81