]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
3 | Forward declares `boost::hana::integral_constant`. | |
4 | ||
5 | @copyright Louis Dionne 2013-2016 | |
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_FWD_INTEGRAL_CONSTANT_HPP | |
11 | #define BOOST_HANA_FWD_INTEGRAL_CONSTANT_HPP | |
12 | ||
13 | #include <boost/hana/config.hpp> | |
14 | #include <boost/hana/detail/operators/adl.hpp> | |
15 | ||
16 | #include <cstddef> | |
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 | |
243 | ||
244 | //! Creates an `integral_constant` holding the given compile-time value. | |
245 | //! @relates hana::integral_constant | |
246 | //! | |
247 | //! Specifically, `integral_c<T, v>` is a `hana::integral_constant` | |
248 | //! holding the compile-time value `v` of an integral type `T`. | |
249 | //! | |
250 | //! | |
251 | //! @tparam T | |
252 | //! The type of the value to hold in the `integral_constant`. | |
253 | //! It must be an integral type. | |
254 | //! | |
255 | //! @tparam v | |
256 | //! The integral value to hold in the `integral_constant`. | |
257 | //! | |
258 | //! | |
259 | //! Example | |
260 | //! ------- | |
261 | //! @snippet example/integral_constant.cpp integral_c | |
262 | template <typename T, T v> | |
263 | constexpr integral_constant<T, v> integral_c{}; | |
264 | ||
265 | ||
266 | //! @relates hana::integral_constant | |
267 | template <bool b> | |
268 | using bool_ = integral_constant<bool, b>; | |
269 | ||
270 | //! @relates hana::integral_constant | |
271 | template <bool b> | |
272 | constexpr bool_<b> bool_c{}; | |
273 | ||
274 | //! @relates hana::integral_constant | |
275 | using true_ = bool_<true>; | |
276 | ||
277 | //! @relates hana::integral_constant | |
278 | constexpr auto true_c = bool_c<true>; | |
279 | ||
280 | //! @relates hana::integral_constant | |
281 | using false_ = bool_<false>; | |
282 | ||
283 | //! @relates hana::integral_constant | |
284 | constexpr auto false_c = bool_c<false>; | |
285 | ||
286 | ||
287 | //! @relates hana::integral_constant | |
288 | template <char c> | |
289 | using char_ = integral_constant<char, c>; | |
290 | ||
291 | //! @relates hana::integral_constant | |
292 | template <char c> | |
293 | constexpr char_<c> char_c{}; | |
294 | ||
295 | ||
296 | //! @relates hana::integral_constant | |
297 | template <short i> | |
298 | using short_ = integral_constant<short, i>; | |
299 | ||
300 | //! @relates hana::integral_constant | |
301 | template <short i> | |
302 | constexpr short_<i> short_c{}; | |
303 | ||
304 | ||
305 | //! @relates hana::integral_constant | |
306 | template <unsigned short i> | |
307 | using ushort_ = integral_constant<unsigned short, i>; | |
308 | ||
309 | //! @relates hana::integral_constant | |
310 | template <unsigned short i> | |
311 | constexpr ushort_<i> ushort_c{}; | |
312 | ||
313 | ||
314 | //! @relates hana::integral_constant | |
315 | template <int i> | |
316 | using int_ = integral_constant<int, i>; | |
317 | ||
318 | //! @relates hana::integral_constant | |
319 | template <int i> | |
320 | constexpr int_<i> int_c{}; | |
321 | ||
322 | ||
323 | //! @relates hana::integral_constant | |
324 | template <unsigned int i> | |
325 | using uint = integral_constant<unsigned int, i>; | |
326 | ||
327 | //! @relates hana::integral_constant | |
328 | template <unsigned int i> | |
329 | constexpr uint<i> uint_c{}; | |
330 | ||
331 | ||
332 | //! @relates hana::integral_constant | |
333 | template <long i> | |
334 | using long_ = integral_constant<long, i>; | |
335 | ||
336 | //! @relates hana::integral_constant | |
337 | template <long i> | |
338 | constexpr long_<i> long_c{}; | |
339 | ||
340 | ||
341 | //! @relates hana::integral_constant | |
342 | template <unsigned long i> | |
343 | using ulong = integral_constant<unsigned long, i>; | |
344 | ||
345 | //! @relates hana::integral_constant | |
346 | template <unsigned long i> | |
347 | constexpr ulong<i> ulong_c{}; | |
348 | ||
349 | ||
350 | //! @relates hana::integral_constant | |
351 | template <long long i> | |
352 | using llong = integral_constant<long long, i>; | |
353 | ||
354 | //! @relates hana::integral_constant | |
355 | template <long long i> | |
356 | constexpr llong<i> llong_c{}; | |
357 | ||
358 | ||
359 | //! @relates hana::integral_constant | |
360 | template <unsigned long long i> | |
361 | using ullong = integral_constant<unsigned long long, i>; | |
362 | ||
363 | //! @relates hana::integral_constant | |
364 | template <unsigned long long i> | |
365 | constexpr ullong<i> ullong_c{}; | |
366 | ||
367 | ||
368 | //! @relates hana::integral_constant | |
369 | template <std::size_t i> | |
370 | using size_t = integral_constant<std::size_t, i>; | |
371 | ||
372 | //! @relates hana::integral_constant | |
373 | template <std::size_t i> | |
374 | constexpr size_t<i> size_c{}; | |
375 | ||
376 | ||
377 | namespace literals { | |
378 | //! Creates a `hana::integral_constant` from a literal. | |
379 | //! @relatesalso boost::hana::integral_constant | |
380 | //! | |
381 | //! The literal is parsed at compile-time and the result is returned | |
382 | //! as a `llong<...>`. | |
383 | //! | |
384 | //! @note | |
385 | //! We use `llong<...>` instead of `ullong<...>` because using an | |
386 | //! unsigned type leads to unexpected behavior when doing stuff like | |
387 | //! `-1_c`. If we used an unsigned type, `-1_c` would be something | |
388 | //! like `ullong<-1>` which is actually `ullong<something huge>`. | |
389 | //! | |
390 | //! | |
391 | //! Example | |
392 | //! ------- | |
393 | //! @snippet example/integral_constant.cpp literals | |
394 | template <char ...c> | |
395 | constexpr auto operator"" _c(); | |
396 | } | |
397 | BOOST_HANA_NAMESPACE_END | |
398 | ||
399 | #endif // !BOOST_HANA_FWD_INTEGRAL_CONSTANT_HPP |