]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
b32b8144 FG |
3 | Defines the barebones `boost::hana::integral_constant` template, but no |
4 | operations on it. | |
7c673cae | 5 | |
b32b8144 | 6 | @copyright Louis Dionne 2013-2017 |
7c673cae FG |
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 | ||
b32b8144 FG |
11 | #ifndef BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP |
12 | #define BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP | |
7c673cae FG |
13 | |
14 | #include <boost/hana/config.hpp> | |
15 | #include <boost/hana/detail/operators/adl.hpp> | |
16 | ||
7c673cae FG |
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> | |
168 | 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 | struct integral_constant | |
235 | : std::integral_constant<T, v> | |
236 | , detail::operators::adl<integral_constant<T, v>> | |
237 | { | |
238 | using type = integral_constant; // override std::integral_constant::type | |
239 | static constexpr ic_detail::times_t<T, v> times{}; | |
240 | using hana_tag = integral_constant_tag<T>; | |
241 | }; | |
242 | #endif | |
7c673cae FG |
243 | BOOST_HANA_NAMESPACE_END |
244 | ||
b32b8144 | 245 | #endif // !BOOST_HANA_DETAIL_INTEGRAL_CONSTANT_HPP |