1 /*!
2 @file
3 Defines the barebones `boost::hana::integral_constant` template, but no
4 operations on it.
5 
6 @copyright Louis Dionne 2013-2017
7 Distributed under the Boost Software License, Version 1.0.
8 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
9  */
10 
11 #ifndef BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP
12 #define BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP
13 
14 #include <boost/hana/config.hpp>
15 #include <boost/hana/detail/operators/adl.hpp>
16 
17 #include <type_traits>
18 
19 
20 BOOST_HANA_NAMESPACE_BEGIN
21     //! Tag representing `hana::integral_constant`.
22     //! @relates hana::integral_constant
23     template <typename T>
24     struct integral_constant_tag {
25         using value_type = T;
26     };
27 
28     namespace ic_detail {
29         template <typename T, T v>
30         struct with_index_t {
31             template <typename F>
32             constexpr void operator()(F&& f) const;
33         };
34 
35         template <typename T, T v>
36         struct times_t {
37             static constexpr with_index_t<T, v> with_index{};
38 
39             template <typename F>
40             constexpr void operator()(F&& f) const;
41         };
42     }
43 
44     //! @ingroup group-datatypes
45     //! Compile-time value of an integral type.
46     //!
47     //! An `integral_constant` is an object that represents a compile-time
48     //! integral value. As the name suggests, `hana::integral_constant` is
49     //! basically equivalent to `std::integral_constant`, except that
50     //! `hana::integral_constant` also provide other goodies to make them
51     //! easier to use, like arithmetic operators and similar features. In
52     //! particular, `hana::integral_constant` is guaranteed to inherit from
53     //! the corresponding `std::integral_constant`, and hence have the same
54     //! members and capabilities. The sections below explain the extensions
55     //! to `std::integral_constant` provided by `hana::integral_constant`.
56     //!
57     //!
58     //! Arithmetic operators
59     //! --------------------
60     //! `hana::integral_constant` provides arithmetic operators that return
61     //! `hana::integral_constant`s to ease writing compile-time arithmetic:
62     //! @snippet example/integral_constant.cpp operators
63     //!
64     //! It is pretty important to realize that these operators return other
65     //! `integral_constant`s, not normal values of an integral type.
66     //! Actually, all those operators work pretty much in the same way.
67     //! Simply put, for an operator `@`,
68     //! @code
69     //!     integral_constant<T, x>{} @ integral_constant<T, y>{} == integral_constant<T, x @ y>{}
70     //! @endcode
71     //!
72     //! The fact that the operators return `Constant`s is very important
73     //! because it allows all the information that's known at compile-time
74     //! to be conserved as long as it's only used with other values known at
75     //! compile-time. It is also interesting to observe that whenever an
76     //! `integral_constant` is combined with a normal runtime value, the
77     //! result will be a runtime value (because of the implicit conversion).
78     //! In general, this gives us the following table
79     //!
80     //! left operand        | right operand       | result
81     //! :-----------------: | :-----------------: | :-----------------:
82     //! `integral_constant` | `integral_constant` | `integral_constant`
83     //! `integral_constant` | runtime             | runtime
84     //! runtime             | `integral_constant` | runtime
85     //! runtime             | runtime             | runtime
86     //!
87     //! The full range of provided operators is
88     //! - Arithmetic: binary `+`, binary `-`, `/`, `*`, `%`, unary `+`, unary `-`
89     //! - Bitwise: `~`, `&`, `|`, `^`, `<<`, `>>`
90     //! - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`
91     //! - %Logical: `||`, `&&`, `!`
92     //!
93     //!
94     //! Construction with user-defined literals
95     //! ---------------------------------------
96     //! `integral_constant`s of type `long long` can be created with the
97     //! `_c` user-defined literal, which is contained in the `literals`
98     //! namespace:
99     //! @snippet example/integral_constant.cpp literals
100     //!
101     //!
102     //! Modeled concepts
103     //! ----------------
104     //! 1. `Constant` and `IntegralConstant`\n
105     //! An `integral_constant` is a model of the `IntegralConstant` concept in
106     //! the most obvious way possible. Specifically,
107     //! @code
108     //!     integral_constant<T, v>::value == v // of type T
109     //! @endcode
110     //! The model of `Constant` follows naturally from the model of `IntegralConstant`, i.e.
111     //! @code
112     //!     value<integral_constant<T, v>>() == v // of type T
113     //! @endcode
114     //!
115     //! 2. `Comparable`, `Orderable`, `Logical`, `Monoid`, `Group`, `Ring`, and `EuclideanRing`, `Hashable`\n
116     //! Those models are exactly those provided for `Constant`s, which are
117     //! documented in their respective concepts.
118 #ifdef BOOST_HANA_DOXYGEN_INVOKED
119     template <typename T, T v>
120     struct integral_constant {
121         //! Call a function n times.
122         //!
123         //! `times` allows a nullary function to be invoked `n` times:
124         //! @code
125         //!     int_<3>::times(f)
126         //! @endcode
127         //! should be expanded by any decent compiler to
128         //! @code
129         //!     f(); f(); f();
130         //! @endcode
131         //!
132         //! This can be useful in several contexts, e.g. for loop unrolling:
133         //! @snippet example/integral_constant.cpp times_loop_unrolling
134         //!
135         //! Note that `times` is really a static function object, not just a
136         //! static function. This allows `int_<n>::%times` to be passed to
137         //! higher-order algorithms:
138         //! @snippet example/integral_constant.cpp times_higher_order
139         //!
140         //! Also, since static members can be accessed using both the `.` and
141         //! the `::` syntax, one can take advantage of this (loophole?) to
142         //! call `times` on objects just as well as on types:
143         //! @snippet example/integral_constant.cpp from_object
144         //!
145         //! @note
146         //! `times` is equivalent to the `hana::repeat` function, which works
147         //! on an arbitrary `IntegralConstant`.
148         //!
149         //! Sometimes, it is also useful to know the index we're at inside the
150         //! function. This can be achieved by using `times.with_index`:
151         //! @snippet example/integral_constant.cpp times_with_index_runtime
152         //!
153         //! Remember that `times` is a _function object_, and hence it can
154         //! have subobjects. `with_index` is just a function object nested
155         //! inside `times`, which allows for this nice little interface. Also
156         //! note that the indices passed to the function are `integral_constant`s;
157         //! they are known at compile-time. Hence, we can do compile-time stuff
158         //! with them, like indexing inside a tuple:
159         //! @snippet example/integral_constant.cpp times_with_index_compile_time
160         //!
161         //! @note
162         //! `times.with_index(f)` guarantees that the calls to `f` will be
163         //! done in order of ascending index. In other words, `f` will be
164         //! called as `f(0)`, `f(1)`, `f(2)`, etc., but with `integral_constant`s
165         //! instead of normal integers. Side effects can also be done in the
166         //! function passed to `times` and `times.with_index`.
167         template <typename F>
timesintegral_constant168         static constexpr void times(F&& f) {
169             f(); f(); ... f(); // n times total
170         }
171 
172         //! Equivalent to `hana::plus`
173         template <typename X, typename Y>
174         friend constexpr auto operator+(X&& x, Y&& y);
175 
176         //! Equivalent to `hana::minus`
177         template <typename X, typename Y>
178         friend constexpr auto operator-(X&& x, Y&& y);
179 
180         //! Equivalent to `hana::negate`
181         template <typename X>
182         friend constexpr auto operator-(X&& x);
183 
184         //! Equivalent to `hana::mult`
185         template <typename X, typename Y>
186         friend constexpr auto operator*(X&& x, Y&& y);
187 
188         //! Equivalent to `hana::div`
189         template <typename X, typename Y>
190         friend constexpr auto operator/(X&& x, Y&& y);
191 
192         //! Equivalent to `hana::mod`
193         template <typename X, typename Y>
194         friend constexpr auto operator%(X&& x, Y&& y);
195 
196         //! Equivalent to `hana::equal`
197         template <typename X, typename Y>
198         friend constexpr auto operator==(X&& x, Y&& y);
199 
200         //! Equivalent to `hana::not_equal`
201         template <typename X, typename Y>
202         friend constexpr auto operator!=(X&& x, Y&& y);
203 
204         //! Equivalent to `hana::or_`
205         template <typename X, typename Y>
206         friend constexpr auto operator||(X&& x, Y&& y);
207 
208         //! Equivalent to `hana::and_`
209         template <typename X, typename Y>
210         friend constexpr auto operator&&(X&& x, Y&& y);
211 
212         //! Equivalent to `hana::not_`
213         template <typename X>
214         friend constexpr auto operator!(X&& x);
215 
216         //! Equivalent to `hana::less`
217         template <typename X, typename Y>
218         friend constexpr auto operator<(X&& x, Y&& y);
219 
220         //! Equivalent to `hana::greater`
221         template <typename X, typename Y>
222         friend constexpr auto operator>(X&& x, Y&& y);
223 
224         //! Equivalent to `hana::less_equal`
225         template <typename X, typename Y>
226         friend constexpr auto operator<=(X&& x, Y&& y);
227 
228         //! Equivalent to `hana::greater_equal`
229         template <typename X, typename Y>
230         friend constexpr auto operator>=(X&& x, Y&& y);
231     };
232 #else
233     template <typename T, T v>
234 #ifdef BOOST_HANA_WORKAROUND_MSVC_EMPTYBASE
235     struct __declspec(empty_bases) integral_constant
236 #else
237     struct integral_constant
238 #endif
239         : std::integral_constant<T, v>
240         , detail::operators::adl<integral_constant<T, v>>
241     {
242         using type = integral_constant; // override std::integral_constant::type
243         static constexpr ic_detail::times_t<T, v> times{};
244         using hana_tag = integral_constant_tag<T>;
245     };
246 #endif
247 BOOST_HANA_NAMESPACE_END
248 
249 #endif // !BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP
250