]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
3 | Forward declares `boost::hana::Constant`. | |
4 | ||
b32b8144 | 5 | @copyright Louis Dionne 2013-2017 |
7c673cae FG |
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 | |
b32b8144 | 33 | //! convertible to `T`, as determined by `is_convertible`. The |
7c673cae FG |
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 | |
b32b8144 | 62 | //! constexpr auto x = hana::value<decltype(c)>(); |
7c673cae FG |
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 | |
b32b8144 | 149 | //! plus(int_c<1>, 1) == 2 |
7c673cae FG |
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 | |
b32b8144 | 163 | //! constexpr int i = hana::to<int>(int_c<1>); |
7c673cae FG |
164 | //! @endcode |
165 | //! which is an embedding, and | |
166 | //! @code | |
b32b8144 | 167 | //! int i = hana::to<int>(int_c<1>); |
7c673cae FG |
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, | |
b32b8144 FG |
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 | |
7c673cae FG |
175 | //! marked as an embedding, but this also means that code like |
176 | //! @code | |
177 | //! int i = 1; | |
b32b8144 | 178 | //! plus(int_c<1>, i); |
7c673cae FG |
179 | //! @endcode |
180 | //! will be considered valid, which implicitly loses the fact that | |
b32b8144 | 181 | //! `int_c<1>` is a Constant, and hence does not follow the usual rules |
7c673cae FG |
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 | //! | |
92f5a8d4 | 205 | //! [1]: http://en.cppreference.com/w/cpp/named_req/LiteralType |
7c673cae FG |
206 | template <typename C> |
207 | struct Constant; | |
208 | BOOST_HANA_NAMESPACE_END | |
209 | ||
210 | #endif // !BOOST_HANA_FWD_CONCEPT_CONSTANT_HPP |