]>
Commit | Line | Data |
---|---|---|
1 | /*! | |
2 | @file | |
3 | Forward declares `boost::hana::type` and related utilities. | |
4 | ||
5 | @copyright Louis Dionne 2013-2016 | |
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_TYPE_HPP | |
11 | #define BOOST_HANA_FWD_TYPE_HPP | |
12 | ||
13 | #include <boost/hana/config.hpp> | |
14 | #include <boost/hana/fwd/core/make.hpp> | |
15 | ||
16 | ||
17 | BOOST_HANA_NAMESPACE_BEGIN | |
18 | //! Base class of `hana::type`; used for pattern-matching. | |
19 | //! @relates hana::type | |
20 | //! | |
21 | //! Example | |
22 | //! ------- | |
23 | //! @include example/type/basic_type.cpp | |
24 | template <typename T> | |
25 | struct basic_type; | |
26 | ||
27 | //! @ingroup group-datatypes | |
28 | //! C++ type in value-level representation. | |
29 | //! | |
30 | //! A `type` is a special kind of object representing a C++ type like | |
31 | //! `int`, `void`, `std::vector<float>` or anything else you can imagine. | |
32 | //! | |
33 | //! This page explains how `type`s work at a low level. To gain | |
34 | //! intuition about type-level metaprogramming in Hana, you should | |
35 | //! read the [tutorial section](@ref tutorial-type) on type-level | |
36 | //! computations. | |
37 | //! | |
38 | //! | |
39 | //! @note | |
40 | //! For subtle reasons having to do with ADL, the actual representation of | |
41 | //! `hana::type` is implementation-defined. In particular, `hana::type` | |
42 | //! may be a dependent type, so one should not attempt to do pattern | |
43 | //! matching on it. However, one can assume that `hana::type` _inherits_ | |
44 | //! from `hana::basic_type`, which can be useful when declaring overloaded | |
45 | //! functions: | |
46 | //! @code | |
47 | //! template <typename T> | |
48 | //! void f(hana::basic_type<T>) { | |
49 | //! // do something with T | |
50 | //! } | |
51 | //! @endcode | |
52 | //! | |
53 | //! | |
54 | //! @anchor type_lvalues_and_rvalues | |
55 | //! Lvalues and rvalues | |
56 | //! ------------------- | |
57 | //! When storing `type`s in heterogeneous containers, some algorithms | |
58 | //! will return references to those objects. Since we are primarily | |
59 | //! interested in accessing their nested `::%type`, receiving a reference | |
60 | //! is undesirable; we would end up trying to fetch the nested `::%type` | |
61 | //! inside a reference type, which is a compilation error: | |
62 | //! @code | |
63 | //! auto ts = make_tuple(type_c<int>, type_c<char>); | |
64 | //! using T = decltype(ts[0_c])::type; // error: 'ts[0_c]' is a reference! | |
65 | //! @endcode | |
66 | //! | |
67 | //! For this reason, `type`s provide an overload of the unary `+` | |
68 | //! operator that can be used to turn a lvalue into a rvalue. So when | |
69 | //! using a result which might be a reference to a `type` object, one | |
70 | //! can use `+` to make sure a rvalue is obtained before fetching its | |
71 | //! nested `::%type`: | |
72 | //! @code | |
73 | //! auto ts = make_tuple(type_c<int>, type_c<char>); | |
74 | //! using T = decltype(+ts[0_c])::type; // ok: '+ts[0_c]' is an rvalue | |
75 | //! @endcode | |
76 | //! | |
77 | //! | |
78 | //! Modeled concepts | |
79 | //! ---------------- | |
80 | //! 1. `Comparable`\n | |
81 | //! Two types are equal if and only if they represent the same C++ type. | |
82 | //! Hence, equality is equivalent to the `std::is_same` type trait. | |
83 | //! @include example/type/comparable.cpp | |
84 | //! | |
85 | //! 2. `Hashable`\n | |
86 | //! The hash of a type is just that type itself. In other words, `hash` | |
87 | //! is the identity function on `hana::type`s. | |
88 | //! @include example/type/hashable.cpp | |
89 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
90 | template <typename T> | |
91 | struct type { | |
92 | //! Returns rvalue of self. | |
93 | //! See @ref type_lvalues_and_rvalues "description". | |
94 | constexpr auto operator+() const; | |
95 | ||
96 | //! Equivalent to `hana::equal` | |
97 | template <typename X, typename Y> | |
98 | friend constexpr auto operator==(X&& x, Y&& y); | |
99 | ||
100 | //! Equivalent to `hana::not_equal` | |
101 | template <typename X, typename Y> | |
102 | friend constexpr auto operator!=(X&& x, Y&& y); | |
103 | }; | |
104 | #else | |
105 | template <typename T> | |
106 | struct type_impl; | |
107 | ||
108 | template <typename T> | |
109 | using type = typename type_impl<T>::_; | |
110 | #endif | |
111 | ||
112 | //! Tag representing `hana::type`. | |
113 | //! @relates hana::type | |
114 | struct type_tag { }; | |
115 | ||
116 | //! Creates an object representing the C++ type `T`. | |
117 | //! @relates hana::type | |
118 | template <typename T> | |
119 | constexpr type<T> type_c{}; | |
120 | ||
121 | //! `decltype` keyword, lifted to Hana. | |
122 | //! @relates hana::type | |
123 | //! | |
124 | //! @deprecated | |
125 | //! The semantics of `decltype_` can be confusing, and `hana::typeid_` | |
126 | //! should be preferred instead. `decltype_` may be removed in the next | |
127 | //! major version of the library. | |
128 | //! | |
129 | //! `decltype_` is somewhat equivalent to `decltype` in that it returns | |
130 | //! the type of an object, except it returns it as a `hana::type` which | |
131 | //! is a first-class citizen of Hana instead of a raw C++ type. | |
132 | //! Specifically, given an object `x`, `decltype_` satisfies | |
133 | //! @code | |
134 | //! decltype_(x) == type_c<decltype(x) with references stripped> | |
135 | //! @endcode | |
136 | //! | |
137 | //! As you can see, `decltype_` will strip any reference from the | |
138 | //! object's actual type. The reason for doing so is explained below. | |
139 | //! However, any `cv`-qualifiers will be retained. Also, when given a | |
140 | //! `hana::type`, `decltype_` is just the identity function. Hence, | |
141 | //! for any C++ type `T`, | |
142 | //! @code | |
143 | //! decltype_(type_c<T>) == type_c<T> | |
144 | //! @endcode | |
145 | //! | |
146 | //! In conjunction with the way `metafunction` & al. are specified, this | |
147 | //! behavior makes it easier to interact with both types and values at | |
148 | //! the same time. However, it does make it impossible to create a `type` | |
149 | //! containing another `type` with `decltype_`. In other words, it is | |
150 | //! not possible to create a `type_c<decltype(type_c<T>)>` with this | |
151 | //! utility, because `decltype_(type_c<T>)` would be just `type_c<T>` | |
152 | //! instead of `type_c<decltype(type_c<T>)>`. This use case is assumed | |
153 | //! to be rare and a hand-coded function can be used if this is needed. | |
154 | //! | |
155 | //! | |
156 | //! ### Rationale for stripping the references | |
157 | //! The rules for template argument deduction are such that a perfect | |
158 | //! solution that always matches `decltype` is impossible. Hence, we | |
159 | //! have to settle on a solution that's good and and consistent enough | |
160 | //! for our needs. One case where matching `decltype`'s behavior is | |
161 | //! impossible is when the argument is a plain, unparenthesized variable | |
162 | //! or function parameter. In that case, `decltype_`'s argument will be | |
163 | //! deduced as a reference to that variable, but `decltype` would have | |
164 | //! given us the actual type of that variable, without references. Also, | |
165 | //! given the current definition of `metafunction` & al., it would be | |
166 | //! mostly useless if `decltype_` could return a reference, because it | |
167 | //! is unlikely that `F` expects a reference in its simplest use case: | |
168 | //! @code | |
169 | //! int i = 0; | |
170 | //! auto result = metafunction<F>(i); | |
171 | //! @endcode | |
172 | //! | |
173 | //! Hence, always discarding references seems to be the least painful | |
174 | //! solution. | |
175 | //! | |
176 | //! | |
177 | //! Example | |
178 | //! ------- | |
179 | //! @include example/type/decltype.cpp | |
180 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
181 | constexpr auto decltype_ = see documentation; | |
182 | #else | |
183 | struct decltype_t { | |
184 | template <typename T> | |
185 | constexpr auto operator()(T&&) const; | |
186 | }; | |
187 | ||
188 | constexpr decltype_t decltype_{}; | |
189 | #endif | |
190 | ||
191 | //! Returns a `hana::type` representing the type of a given object. | |
192 | //! @relates hana::type | |
193 | //! | |
194 | //! `hana::typeid_` is somewhat similar to `typeid` in that it returns | |
195 | //! something that represents the type of an object. However, what | |
196 | //! `typeid` returns represent the _runtime_ type of the object, while | |
197 | //! `hana::typeid_` returns the _static_ type of the object. Specifically, | |
198 | //! given an object `x`, `typeid_` satisfies | |
199 | //! @code | |
200 | //! typeid_(x) == type_c<decltype(x) with ref and cv-qualifiers stripped> | |
201 | //! @endcode | |
202 | //! | |
203 | //! As you can see, `typeid_` strips any reference and cv-qualifier from | |
204 | //! the object's actual type. The reason for doing so is that it faithfully | |
205 | //! models how the language's `typeid` behaves with respect to reference | |
206 | //! and cv-qualifiers, and it also turns out to be the desirable behavior | |
207 | //! most of the time. Also, when given a `hana::type`, `typeid_` is just | |
208 | //! the identity function. Hence, for any C++ type `T`, | |
209 | //! @code | |
210 | //! typeid_(type_c<T>) == type_c<T> | |
211 | //! @endcode | |
212 | //! | |
213 | //! In conjunction with the way `metafunction` & al. are specified, this | |
214 | //! behavior makes it easier to interact with both types and values at | |
215 | //! the same time. However, it does make it impossible to create a `type` | |
216 | //! containing another `type` using `typeid_`. This use case is assumed | |
217 | //! to be rare and a hand-coded function can be used if this is needed. | |
218 | //! | |
219 | //! | |
220 | //! Example | |
221 | //! ------- | |
222 | //! @include example/type/typeid.cpp | |
223 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
224 | constexpr auto typeid_ = see documentation; | |
225 | #else | |
226 | struct typeid_t { | |
227 | template <typename T> | |
228 | constexpr auto operator()(T&&) const; | |
229 | }; | |
230 | ||
231 | constexpr typeid_t typeid_{}; | |
232 | #endif | |
233 | ||
234 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
235 | //! Equivalent to `decltype_`, provided for convenience. | |
236 | //! @relates hana::type | |
237 | //! | |
238 | //! | |
239 | //! Example | |
240 | //! ------- | |
241 | //! @include example/type/make.cpp | |
242 | template <> | |
243 | constexpr auto make<type_tag> = hana::decltype_; | |
244 | #endif | |
245 | ||
246 | //! Equivalent to `make<type_tag>`, provided for convenience. | |
247 | //! @relates hana::type | |
248 | //! | |
249 | //! | |
250 | //! Example | |
251 | //! ------- | |
252 | //! @include example/type/make.cpp | |
253 | constexpr auto make_type = hana::make<type_tag>; | |
254 | ||
255 | //! `sizeof` keyword, lifted to Hana. | |
256 | //! @relates hana::type | |
257 | //! | |
258 | //! `sizeof_` is somewhat equivalent to `sizeof` in that it returns the | |
259 | //! size of an expression or type, but it takes an arbitrary expression | |
260 | //! or a `hana::type` and returns its size as an `integral_constant`. | |
261 | //! Specifically, given an expression `expr`, `sizeof_` satisfies | |
262 | //! @code | |
263 | //! sizeof_(expr) == size_t<sizeof(decltype(expr) with references stripped)> | |
264 | //! @endcode | |
265 | //! | |
266 | //! However, given a `type`, `sizeof_` will simply fetch the size | |
267 | //! of the C++ type represented by that object. In other words, | |
268 | //! @code | |
269 | //! sizeof_(type_c<T>) == size_t<sizeof(T)> | |
270 | //! @endcode | |
271 | //! | |
272 | //! The behavior of `sizeof_` is consistent with that of `decltype_`. | |
273 | //! In particular, see `decltype_`'s documentation to understand why | |
274 | //! references are always stripped by `sizeof_`. | |
275 | //! | |
276 | //! | |
277 | //! Example | |
278 | //! ------- | |
279 | //! @include example/type/sizeof.cpp | |
280 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
281 | constexpr auto sizeof_ = [](auto&& x) { | |
282 | using T = typename decltype(hana::decltype_(x))::type; | |
283 | return hana::size_c<sizeof(T)>; | |
284 | }; | |
285 | #else | |
286 | struct sizeof_t { | |
287 | template <typename T> | |
288 | constexpr auto operator()(T&&) const; | |
289 | }; | |
290 | ||
291 | constexpr sizeof_t sizeof_{}; | |
292 | #endif | |
293 | ||
294 | //! `alignof` keyword, lifted to Hana. | |
295 | //! @relates hana::type | |
296 | //! | |
297 | //! `alignof_` is somewhat equivalent to `alignof` in that it returns the | |
298 | //! alignment required by any instance of a type, but it takes a `type` | |
299 | //! and returns its alignment as an `integral_constant`. Like `sizeof` | |
300 | //! which works for expressions and type-ids, `alignof_` can also be | |
301 | //! called on an arbitrary expression. Specifically, given an expression | |
302 | //! `expr` and a C++ type `T`, `alignof_` satisfies | |
303 | //! @code | |
304 | //! alignof_(expr) == size_t<alignof(decltype(expr) with references stripped)> | |
305 | //! alignof_(type_c<T>) == size_t<alignof(T)> | |
306 | //! @endcode | |
307 | //! | |
308 | //! The behavior of `alignof_` is consistent with that of `decltype_`. | |
309 | //! In particular, see `decltype_`'s documentation to understand why | |
310 | //! references are always stripped by `alignof_`. | |
311 | //! | |
312 | //! | |
313 | //! Example | |
314 | //! ------- | |
315 | //! @include example/type/alignof.cpp | |
316 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
317 | constexpr auto alignof_ = [](auto&& x) { | |
318 | using T = typename decltype(hana::decltype_(x))::type; | |
319 | return hana::size_c<alignof(T)>; | |
320 | }; | |
321 | #else | |
322 | struct alignof_t { | |
323 | template <typename T> | |
324 | constexpr auto operator()(T&&) const; | |
325 | }; | |
326 | ||
327 | constexpr alignof_t alignof_{}; | |
328 | #endif | |
329 | ||
330 | //! Checks whether a SFINAE-friendly expression is valid. | |
331 | //! @relates hana::type | |
332 | //! | |
333 | //! Given a SFINAE-friendly function, `is_valid` returns whether the | |
334 | //! function call is valid with the given arguments. Specifically, given | |
335 | //! a function `f` and arguments `args...`, | |
336 | //! @code | |
337 | //! is_valid(f, args...) == whether f(args...) is valid | |
338 | //! @endcode | |
339 | //! | |
340 | //! The result is returned as a compile-time `Logical`. Furthermore, | |
341 | //! `is_valid` can be used in curried form as follows: | |
342 | //! @code | |
343 | //! is_valid(f)(args...) | |
344 | //! @endcode | |
345 | //! | |
346 | //! This syntax makes it easy to create functions that check the validity | |
347 | //! of a generic expression on any given argument(s). | |
348 | //! | |
349 | //! @warning | |
350 | //! To check whether calling a nullary function `f` is valid, one should | |
351 | //! use the `is_valid(f)()` syntax. Indeed, `is_valid(f /* no args */)` | |
352 | //! will be interpreted as the currying of `is_valid` to `f` rather than | |
353 | //! the application of `is_valid` to `f` and no arguments. | |
354 | //! | |
355 | //! | |
356 | //! Example | |
357 | //! ------- | |
358 | //! @include example/type/is_valid.cpp | |
359 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
360 | constexpr auto is_valid = [](auto&& f) { | |
361 | return [](auto&& ...args) { | |
362 | return whether f(args...) is a valid expression; | |
363 | }; | |
364 | }; | |
365 | #else | |
366 | struct is_valid_t { | |
367 | template <typename F> | |
368 | constexpr auto operator()(F&&) const; | |
369 | ||
370 | template <typename F, typename ...Args> | |
371 | constexpr auto operator()(F&&, Args&&...) const; | |
372 | }; | |
373 | ||
374 | constexpr is_valid_t is_valid{}; | |
375 | #endif | |
376 | ||
377 | //! Lift a template to a Metafunction. | |
378 | //! @ingroup group-Metafunction | |
379 | //! | |
380 | //! Given a template class or template alias `f`, `template_<f>` is a | |
381 | //! `Metafunction` satisfying | |
382 | //! @code | |
383 | //! template_<f>(type_c<x>...) == type_c<f<x...>> | |
384 | //! decltype(template_<f>)::apply<x...>::type == f<x...> | |
385 | //! @endcode | |
386 | //! | |
387 | //! @note | |
388 | //! `template_` can't be SFINAE-friendly right now because of | |
389 | //! [Core issue 1430][1]. | |
390 | //! | |
391 | //! | |
392 | //! Example | |
393 | //! ------- | |
394 | //! @include example/type/template.cpp | |
395 | //! | |
396 | //! [1]: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1430 | |
397 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
398 | template <template <typename ...> class F> | |
399 | constexpr auto template_ = [](basic_type<T>...) { | |
400 | return hana::type_c<F<T...>>; | |
401 | }; | |
402 | #else | |
403 | template <template <typename ...> class F> | |
404 | struct template_t; | |
405 | ||
406 | template <template <typename ...> class F> | |
407 | constexpr template_t<F> template_{}; | |
408 | #endif | |
409 | ||
410 | //! Lift a MPL-style metafunction to a Metafunction. | |
411 | //! @ingroup group-Metafunction | |
412 | //! | |
413 | //! Given a MPL-style metafunction, `metafunction<f>` is a `Metafunction` | |
414 | //! satisfying | |
415 | //! @code | |
416 | //! metafunction<f>(type_c<x>...) == type_c<f<x...>::type> | |
417 | //! decltype(metafunction<f>)::apply<x...>::type == f<x...>::type | |
418 | //! @endcode | |
419 | //! | |
420 | //! | |
421 | //! Example | |
422 | //! ------- | |
423 | //! @include example/type/metafunction.cpp | |
424 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
425 | template <template <typename ...> class F> | |
426 | constexpr auto metafunction = [](basic_type<T>...) { | |
427 | return hana::type_c<typename F<T...>::type>; | |
428 | }; | |
429 | #else | |
430 | template <template <typename ...> class f> | |
431 | struct metafunction_t; | |
432 | ||
433 | template <template <typename ...> class f> | |
434 | constexpr metafunction_t<f> metafunction{}; | |
435 | #endif | |
436 | ||
437 | //! Lift a MPL-style metafunction class to a Metafunction. | |
438 | //! @ingroup group-Metafunction | |
439 | //! | |
440 | //! Given a MPL-style metafunction class, `metafunction_class<f>` is a | |
441 | //! `Metafunction` satisfying | |
442 | //! @code | |
443 | //! metafunction_class<f>(type_c<x>...) == type_c<f::apply<x...>::type> | |
444 | //! decltype(metafunction_class<f>)::apply<x...>::type == f::apply<x...>::type | |
445 | //! @endcode | |
446 | //! | |
447 | //! | |
448 | //! Example | |
449 | //! ------- | |
450 | //! @include example/type/metafunction_class.cpp | |
451 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
452 | template <typename F> | |
453 | constexpr auto metafunction_class = [](basic_type<T>...) { | |
454 | return hana::type_c<typename F::template apply<T...>::type>; | |
455 | }; | |
456 | #else | |
457 | template <typename F> | |
458 | struct metafunction_class_t | |
459 | : metafunction_t<F::template apply> | |
460 | { }; | |
461 | ||
462 | template <typename F> | |
463 | constexpr metafunction_class_t<F> metafunction_class{}; | |
464 | #endif | |
465 | ||
466 | //! Turn a `Metafunction` into a function taking `type`s and returning a | |
467 | //! default-constructed object. | |
468 | //! @ingroup group-Metafunction | |
469 | //! | |
470 | //! Given a `Metafunction` `f`, `integral` returns a new `Metafunction` | |
471 | //! that default-constructs an object of the type returned by `f`. More | |
472 | //! specifically, the following holds: | |
473 | //! @code | |
474 | //! integral(f)(t...) == decltype(f(t...))::type{} | |
475 | //! @endcode | |
476 | //! | |
477 | //! The principal use case for `integral` is to transform `Metafunction`s | |
478 | //! returning a type that inherits from a meaningful base like | |
479 | //! `std::integral_constant` into functions returning e.g. a | |
480 | //! `hana::integral_constant`. | |
481 | //! | |
482 | //! @note | |
483 | //! - This is not a `Metafunction` because it does not return a `type`. | |
484 | //! As such, it would not make sense to make `decltype(integral(f))` | |
485 | //! a MPL metafunction class like the usual `Metafunction`s are. | |
486 | //! | |
487 | //! - When using `integral` with metafunctions returning | |
488 | //! `std::integral_constant`s, don't forget to include the | |
489 | //! boost/hana/ext/std/integral_constant.hpp header to ensure | |
490 | //! Hana can interoperate with the result. | |
491 | //! | |
492 | //! | |
493 | //! Example | |
494 | //! ------- | |
495 | //! @include example/type/integral.cpp | |
496 | #ifdef BOOST_HANA_DOXYGEN_INVOKED | |
497 | constexpr auto integral = [](auto f) { | |
498 | return [](basic_type<T>...) { | |
499 | return decltype(f)::apply<T...>::type{}; | |
500 | }; | |
501 | }; | |
502 | #else | |
503 | template <typename F> | |
504 | struct integral_t; | |
505 | ||
506 | struct make_integral_t { | |
507 | template <typename F> | |
508 | constexpr integral_t<F> operator()(F const&) const | |
509 | { return {}; } | |
510 | }; | |
511 | ||
512 | constexpr make_integral_t integral{}; | |
513 | #endif | |
514 | ||
515 | //! Alias to `integral(metafunction<F>)`, provided for convenience. | |
516 | //! @ingroup group-Metafunction | |
517 | //! | |
518 | //! | |
519 | //! Example | |
520 | //! ------- | |
521 | //! @include example/type/trait.cpp | |
522 | template <template <typename ...> class F> | |
523 | constexpr auto trait = hana::integral(hana::metafunction<F>); | |
524 | BOOST_HANA_NAMESPACE_END | |
525 | ||
526 | #endif // !BOOST_HANA_FWD_TYPE_HPP |