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