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