C++ type in value-level representation.
A type is a special kind of object representing a C++ type like int, void, std::vector<float> or anything else you can imagine.
This page explains how types work at a low level. To gain intuition about type-level metaprogramming in Hana, you should read the tutorial section on type-level computations.
hana::type is implementation-defined. In particular, hana::type may be a dependent type, so one should not attempt to do pattern matching on it. However, one can assume that hana::type inherits from hana::basic_type, which can be useful when declaring overloaded functions: When storing types in heterogeneous containers, some algorithms will return references to those objects. Since we are primarily interested in accessing their nested ::type, receiving a reference is undesirable; we would end up trying to fetch the nested ::type inside a reference type, which is a compilation error:
For this reason, types provide an overload of the unary + operator that can be used to turn a lvalue into a rvalue. So when using a result which might be a reference to a type object, one can use + to make sure a rvalue is obtained before fetching its nested ::type:
Comparablestd::is_same type trait. Hashablehash is the identity function on hana::types. Synopsis of associated functions | |
| template<typename T > | |
| constexpr type< T > | type_c {} |
Creates an object representing the C++ type T. More... | |
| constexpr auto | decltype_ = see documentation |
decltype keyword, lifted to Hana. More... | |
| template<> | |
| constexpr auto | make< type_tag > = hana::decltype_ |
Equivalent to decltype_, provided for convenience. More... | |
| constexpr auto | make_type = hana::make<type_tag> |
Equivalent to make<type_tag>, provided for convenience. More... | |
| constexpr auto | sizeof_ |
sizeof keyword, lifted to Hana. More... | |
| constexpr auto | alignof_ |
alignof keyword, lifted to Hana. More... | |
| constexpr auto | is_valid |
| Checks whether a SFINAE-friendly expression is valid. More... | |
Friends | |
| template<typename X , typename Y > | |
| constexpr auto | operator== (X &&x, Y &&y) |
Equivalent to hana::equal | |
| template<typename X , typename Y > | |
| constexpr auto | operator!= (X &&x, Y &&y) |
Equivalent to hana::not_equal | |
Public Member Functions | |
| constexpr auto | operator+ () const |
| Returns rvalue of self. See description. | |
Creates an object representing the C++ type T.
|
related |
decltype keyword, lifted to Hana.
decltype_ is somewhat equivalent to decltype in that it returns the type of an object, except it returns it as a hana::type which is a first-class citizen of Hana instead of a raw C++ type. Specifically, given an object x, decltype_ satisfies
As you can see, decltype_ will strip any reference from the object's actual type. The reason for doing so is explained below. However, any cv-qualifiers will be retained. Also, when given a hana::type, decltype_ is just the identity function. Hence, for any C++ type T,
In conjunction with the way metafunction & al. are specified, this behavior makes it easier to interact with both types and values at the same time. However, it does make it impossible to create a type containing another type with decltype_. In other words, it is not possible to create a type_c<decltype(type_c<T>)> with this utility, because decltype_(type_c<T>) would be just type_c<T> instead of type_c<decltype(type_c<T>)>. This use case is assumed to be rare and a hand-coded function can be used if this is needed.
The rules for template argument deduction are such that a perfect solution that always matches decltype is impossible. Hence, we have to settle on a solution that's good and and consistent enough for our needs. One case where matching decltype's behavior is impossible is when the argument is a plain, unparenthesized variable or function parameter. In that case, decltype_'s argument will be deduced as a reference to that variable, but decltype would have given us the actual type of that variable, without references. Also, given the current definition of metafunction & al., it would be mostly useless if decltype_ could return a reference, because it is unlikely that F expects a reference in its simplest use case:
Hence, always discarding references seems to be the least painful solution.
Equivalent to decltype_, provided for convenience.
|
related |
Equivalent to make<type_tag>, provided for convenience.
|
related |
sizeof keyword, lifted to Hana.
sizeof_ is somewhat equivalent to sizeof in that it returns the size of an expression or type, but it takes an arbitrary expression or a hana::type and returns its size as an integral_constant. Specifically, given an expression expr, sizeof_ satisfies
However, given a type, sizeof_ will simply fetch the size of the C++ type represented by that object. In other words,
The behavior of sizeof_ is consistent with that of decltype_. In particular, see decltype_'s documentation to understand why references are always stripped by sizeof_.
|
related |
alignof keyword, lifted to Hana.
alignof_ is somewhat equivalent to alignof in that it returns the alignment required by any instance of a type, but it takes a type and returns its alignment as an integral_constant. Like sizeof which works for expressions and type-ids, alignof_ can also be called on an arbitrary expression. Specifically, given an expression expr and a C++ type T, alignof_ satisfies
The behavior of alignof_ is consistent with that of decltype_. In particular, see decltype_'s documentation to understand why references are always stripped by alignof_.
|
related |
Checks whether a SFINAE-friendly expression is valid.
Given a SFINAE-friendly function, is_valid returns whether the function call is valid with the given arguments. Specifically, given a function f and arguments args...,
The result is returned as a compile-time Logical. Furthermore, is_valid can be used in curried form as follows:
This syntax makes it easy to create functions that check the validity of a generic expression on any given argument(s).
f is valid, one should use the is_valid(f)() syntax. Indeed, is_valid(f /* no args */) will be interpreted as the currying of is_valid to f rather than the application of is_valid to f and no arguments.