1 /*! 2 @file 3 Forward declares `boost::hana::Constant`. 4 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 10 #ifndef BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP 11 #define BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP 12 13 #include <boost/hana/config.hpp> 14 15 16 BOOST_HANA_NAMESPACE_BEGIN 17 //! @ingroup group-concepts 18 //! @defgroup group-Constant Constant 19 //! The `Constant` concept represents data that can be manipulated at 20 //! compile-time. 21 //! 22 //! At its core, `Constant` is simply a generalization of the principle 23 //! behind `std::integral_constant` to all types that can be constructed 24 //! at compile-time, i.e. to all types with a `constexpr` constructor 25 //! (also called [Literal types][1]). More specifically, a `Constant` is 26 //! an object from which a `constexpr` value may be obtained (through the 27 //! `value` method) regardless of the `constexpr`ness of the object itself. 28 //! 29 //! All `Constant`s must be somewhat equivalent, in the following sense. 30 //! Let `C(T)` and `D(U)` denote the tags of `Constant`s holding objects 31 //! of type `T` and `U`, respectively. Then, an object with tag `D(U)` 32 //! must be convertible to an object with tag `C(T)` whenever `U` is 33 //! convertible to `T`, as determined by `is_convertible`. The 34 //! interpretation here is that a `Constant` is just a box holding 35 //! an object of some type, and it should be possible to swap between 36 //! boxes whenever the objects inside the boxes can be swapped. 37 //! 38 //! Because of this last requirement, one could be tempted to think that 39 //! specialized "boxes" like `std::integral_constant` are prevented from 40 //! being `Constant`s because they are not able to hold objects of any 41 //! type `T` (`std::integral_constant` may only hold integral types). 42 //! This is false; the requirement should be interpreted as saying that 43 //! whenever `C(T)` is _meaningful_ (e.g. only when `T` is integral for 44 //! `std::integral_constant`) _and_ there exists a conversion from `U` 45 //! to `T`, then a conversion from `D(U)` to `C(T)` should also exist. 46 //! The precise requirements for being a `Constant` are embodied in the 47 //! following laws. 48 //! 49 //! 50 //! Minimal complete definition 51 //! --------------------------- 52 //! `value` and `to`, satisfying the laws below. 53 //! 54 //! 55 //! Laws 56 //! ---- 57 //! Let `c` be an object of with tag `C`, which represents a `Constant` 58 //! holding an object with tag `T`. The first law ensures that the value 59 //! of the wrapped object is always a constant expression by requiring 60 //! the following to be well-formed: 61 //! @code 62 //! constexpr auto x = hana::value<decltype(c)>(); 63 //! @endcode 64 //! 65 //! This means that the `value` function must return an object that can 66 //! be constructed at compile-time. It is important to note how `value` 67 //! only receives the type of the object and not the object itself. 68 //! This is the core of the `Constant` concept; it means that the only 69 //! information required to implement `value` must be stored in the _type_ 70 //! of its argument, and hence be available statically. 71 //! 72 //! The second law that must be satisfied ensures that `Constant`s are 73 //! basically dumb boxes, which makes it possible to provide models for 74 //! many concepts without much work from the user. The law simply asks 75 //! for the following expression to be valid: 76 //! @code 77 //! to<C>(i) 78 //! @endcode 79 //! where, `i` is an _arbitrary_ `Constant` holding an internal value 80 //! with a tag that can be converted to `T`, as determined by the 81 //! `hana::is_convertible` metafunction. In other words, whenever `U` is 82 //! convertible to `T`, a `Constant` holding a `U` is convertible to 83 //! a `Constant` holding a `T`, if such a `Constant` can be created. 84 //! 85 //! Finally, the tag `C` must provide a nested `value_type` alias to `T`, 86 //! which allows us to query the tag of the inner value held by objects 87 //! with tag `C`. In other words, the following must be true for any 88 //! object `c` with tag `C`: 89 //! @code 90 //! std::is_same< 91 //! C::value_type, 92 //! tag_of<decltype(hana::value(c))>::type 93 //! >::value 94 //! @endcode 95 //! 96 //! 97 //! Refined concepts 98 //! ---------------- 99 //! In certain cases, a `Constant` can automatically be made a model of 100 //! another concept. In particular, if a `Constant` `C` is holding an 101 //! object of tag `T`, and if `T` models a concept `X`, then `C` may 102 //! in most cases model `X` by simply performing whatever operation is 103 //! required on its underlying value, and then wrapping the result back 104 //! in a `C`. 105 //! 106 //! More specifically, if a `Constant` `C` has an underlying value 107 //! (`C::value_type`) which is a model of `Comparable`, `Orderable`, 108 //! `Logical`, or `Monoid` up to `EuclideanRing`, then `C` must also 109 //! be a model of those concepts. In other words, when `C::value_type` 110 //! models one of the listed concepts, `C` itself must also model that 111 //! concept. However, note that free models are provided for all of 112 //! those concepts, so no additional work must be done. 113 //! 114 //! While it would be possible in theory to provide models for concepts 115 //! like `Foldable` too, only a couple of concepts are useful to have as 116 //! `Constant` in practice. Providing free models for the concepts listed 117 //! above is useful because it allows various types of integral constants 118 //! (`std::integral_constant`, `mpl::integral_c`, etc...) to easily have 119 //! models for them just by defining the `Constant` concept. 120 //! 121 //! @remark 122 //! An interesting observation is that `Constant` is actually the 123 //! canonical embedding of the subcategory of `constexpr` things 124 //! into the Hana category, which contains everything in this library. 125 //! Hence, whatever is true in that subcategory is also true here, via 126 //! this functor. This is why we can provide models of any concept that 127 //! works on `constexpr` things for Constants, by simply passing them 128 //! through that embedding. 129 //! 130 //! 131 //! Concrete models 132 //! --------------- 133 //! `hana::integral_constant` 134 //! 135 //! 136 //! Provided conversion to the tag of the underlying value 137 //! ------------------------------------------------------ 138 //! Any `Constant` `c` holding an underlying value of tag `T` is 139 //! convertible to any tag `U` such that `T` is convertible to `U`. 140 //! Specifically, the conversion is equivalent to 141 //! @code 142 //! to<U>(c) == to<U>(value<decltype(c)>()) 143 //! @endcode 144 //! 145 //! Also, those conversions are marked as an embedding whenever the 146 //! conversion of underlying types is an embedding. This is to allow 147 //! Constants to inter-operate with `constexpr` objects easily: 148 //! @code 149 //! plus(int_c<1>, 1) == 2 150 //! @endcode 151 //! 152 //! Strictly speaking, __this is sometimes a violation__ of what it means 153 //! to be an embedding. Indeed, while there exists an embedding from any 154 //! Constant to a `constexpr` object (since Constant is just the canonical 155 //! inclusion), there is no embedding from a Constant to a runtime 156 //! object since we would lose the ability to define the `value` method 157 //! (the `constexpr`ness of the object would have been lost). Since there 158 //! is no way to distinguish `constexpr` and non-`constexpr` objects based 159 //! on their type, Hana has no way to know whether the conversion is to a 160 //! `constexpr` object of not. In other words, the `to` method has no way 161 //! to differentiate between 162 //! @code 163 //! constexpr int i = hana::to<int>(int_c<1>); 164 //! @endcode 165 //! which is an embedding, and 166 //! @code 167 //! int i = hana::to<int>(int_c<1>); 168 //! @endcode 169 //! 170 //! which isn't. To be on the safer side, we could mark the conversion 171 //! as not-an-embedding. However, if e.g. the conversion from 172 //! `integral_constant_tag<int>` to `int` was not marked as an embedding, 173 //! we would have to write `plus(to<int>(int_c<1>), 1)` instead of just 174 //! `plus(int_c<1>, 1)`, which is cumbersome. Hence, the conversion is 175 //! marked as an embedding, but this also means that code like 176 //! @code 177 //! int i = 1; 178 //! plus(int_c<1>, i); 179 //! @endcode 180 //! will be considered valid, which implicitly loses the fact that 181 //! `int_c<1>` is a Constant, and hence does not follow the usual rules 182 //! for cross-type operations in Hana. 183 //! 184 //! 185 //! Provided common data type 186 //! ------------------------- 187 //! Because of the requirement that `Constant`s be interchangeable when 188 //! their contents are compatible, two `Constant`s `A` and `B` will have 189 //! a common data type whenever `A::value_type` and `B::value_type` have 190 //! one. Their common data type is an unspecified `Constant` `C` such 191 //! that `C::value_type` is exactly `common_t<A::value_type, B::value_type>`. 192 //! A specialization of the `common` metafunction is provided for 193 //! `Constant`s to reflect this. 194 //! 195 //! In the same vein, a common data type is also provided from any 196 //! constant `A` to a type `T` such that `A::value_type` and `T` share 197 //! a common type. The common type between `A` and `T` is obviously the 198 //! common type between `A::value_type` and `T`. As explained above in 199 //! the section on conversions, this is sometimes a violation of the 200 //! definition of a common type, because there must be an embedding 201 //! to the common type, which is not always the case. For the same 202 //! reasons as explained above, this common type is still provided. 203 //! 204 //! 205 //! [1]: http://en.cppreference.com/w/cpp/named_req/LiteralType 206 template <typename C> 207 struct Constant; 208 BOOST_HANA_NAMESPACE_END 209 210 #endif // !BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP 211