integral_constant.hpp 9.8 KB

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