| 1 | /*! |
| 2 | @file |
| 3 | Forward declares `boost::hana::Constant`. |
| 4 | |
| 5 | Copyright Louis Dionne 2013-2022 |
| 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 | namespace boost { namespace hana { |
| 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 | }} // end namespace boost::hana |
| 209 | |
| 210 | #endif // !BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP |
| 211 | |