• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 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, 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     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     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     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     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
__anon09778f620102(auto&& x) 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     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
__anon09778f620202(auto&& x) 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     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
__anon09778f620302(auto&& f) 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     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>
__anon09778f620502(basic_type<T>...) 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     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>
__anon09778f620602(basic_type<T>...) 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     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>
__anon09778f620702(basic_type<T>...) 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     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
__anon09778f620802(auto f) 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>
operator ()make_integral_t524         constexpr integral_t<F> operator()(F const&) const
525         { return {}; }
526     };
527 
528     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     constexpr auto trait = hana::integral(hana::metafunction<F>);
540 BOOST_HANA_NAMESPACE_END
541 
542 #endif // !BOOST_HANA_FWD_TYPE_HPP
543