Boost.Hana  1.5.0
Your standard library for metaprogramming
boost::hana::type< T > Struct Template Reference

Description

template<typename T>
struct boost::hana::type< T >

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.

Note
For subtle reasons, the actual representation of 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:
template <typename T>
void f(hana::basic_type<T>) {
// do something with T
}
The full story is that ADL causes template arguments to be instantiated. Hence, if hana::type were defined naively, expressions like hana::type<T>{} == hana::type<U>{} would cause both T and U to be instantiated. This is usually not a problem, except when T or U should not be instantiated. To avoid these instantiations, hana::type is implemented using some cleverness, and that is why the representation is implementation-defined. When that behavior is not required, hana::basic_type can be used instead.

Lvalues and rvalues

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:

auto ts = make_tuple(type_c<int>, type_c<char>);
using T = decltype(ts[0_c])::type; // error: 'ts[0_c]' is a reference!

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:

auto ts = make_tuple(type_c<int>, type_c<char>);
using T = decltype(+ts[0_c])::type; // ok: '+ts[0_c]' is an rvalue

Modeled concepts

  1. Comparable
    Two types are equal if and only if they represent the same C++ type. Hence, equality is equivalent to the std::is_same type trait.
    // Copyright Louis Dionne 2013-2017
    // Distributed under the Boost Software License, Version 1.0.
    // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
    namespace hana = boost::hana;
    struct T;
    struct U;
    BOOST_HANA_CONSTANT_CHECK(hana::type_c<T> == hana::type_c<T>);
    BOOST_HANA_CONSTANT_CHECK(hana::type_c<T> != hana::type_c<U>);
    int main() { }
  2. Hashable
    The hash of a type is just that type itself. In other words, hash is the identity function on hana::types.
    // Copyright Louis Dionne 2013-2017
    // Distributed under the Boost Software License, Version 1.0.
    // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
    namespace hana = boost::hana;
    // `hana::hash` is the identity on `hana::type`s.
    hana::hash(hana::type_c<int>),
    hana::type_c<int>
    ));
    hana::hash(hana::type_c<void>),
    hana::type_c<void>
    ));
    int main() { }

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...
 
constexpr auto typeid_ = see documentation
 Returns a hana::type representing the type of a given object. 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.
 

Associated functions

template<typename T >
template<typename T >
constexpr type<T> type_c {}
related

Creates an object representing the C++ type T.

template<typename T >
constexpr auto decltype_ = see documentation
related

decltype keyword, lifted to Hana.

Deprecated:
The semantics of decltype_ can be confusing, and hana::typeid_ should be preferred instead. decltype_ may be removed in the next major version of the library.

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

decltype_(x) == type_c<decltype(x) with references stripped>

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,

decltype_(type_c<T>) == type_c<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.

Rationale for stripping the references

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:

int i = 0;
auto result = metafunction<F>(i);

Hence, always discarding references seems to be the least painful solution.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
struct X { };
BOOST_HANA_CONSTANT_CHECK(hana::decltype_(X{}) == hana::type_c<X>);
BOOST_HANA_CONSTANT_CHECK(hana::decltype_(hana::type_c<X>) == hana::type_c<X>);
BOOST_HANA_CONSTANT_CHECK(hana::decltype_(1) == hana::type_c<int>);
static int const& i = 1;
BOOST_HANA_CONSTANT_CHECK(hana::decltype_(i) == hana::type_c<int const>);
int main() { }
template<typename T >
constexpr auto typeid_ = see documentation
related

Returns a hana::type representing the type of a given object.

hana::typeid_ is somewhat similar to typeid in that it returns something that represents the type of an object. However, what typeid returns represent the runtime type of the object, while hana::typeid_ returns the static type of the object. Specifically, given an object x, typeid_ satisfies

typeid_(x) == type_c<decltype(x) with ref and cv-qualifiers stripped>

As you can see, typeid_ strips any reference and cv-qualifier from the object's actual type. The reason for doing so is that it faithfully models how the language's typeid behaves with respect to reference and cv-qualifiers, and it also turns out to be the desirable behavior most of the time. Also, when given a hana::type, typeid_ is just the identity function. Hence, for any C++ type T,

typeid_(type_c<T>) == type_c<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 using typeid_. This use case is assumed to be rare and a hand-coded function can be used if this is needed.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <string>
namespace hana = boost::hana;
struct Cat { std::string name; };
struct Dog { std::string name; };
struct Fish { std::string name; };
bool operator==(Cat const& a, Cat const& b) { return a.name == b.name; }
bool operator!=(Cat const& a, Cat const& b) { return a.name != b.name; }
bool operator==(Dog const& a, Dog const& b) { return a.name == b.name; }
bool operator!=(Dog const& a, Dog const& b) { return a.name != b.name; }
bool operator==(Fish const& a, Fish const& b) { return a.name == b.name; }
bool operator!=(Fish const& a, Fish const& b) { return a.name != b.name; }
int main() {
hana::tuple<Cat, Fish, Dog, Fish> animals{
Cat{"Garfield"}, Fish{"Jaws"}, Dog{"Beethoven"}, Fish{"Nemo"}
};
auto mammals = hana::remove_if(animals, [](auto const& a) {
return hana::typeid_(a) == hana::type<Fish>{};
});
BOOST_HANA_RUNTIME_CHECK(mammals == hana::make_tuple(Cat{"Garfield"}, Dog{"Beethoven"}));
}
template<typename T >
template<>
constexpr auto make< type_tag > = hana::decltype_
related

Equivalent to decltype_, provided for convenience.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
struct X { };
BOOST_HANA_CONSTANT_CHECK(hana::make<hana::type_tag>(X{}) == hana::type_c<X>);
BOOST_HANA_CONSTANT_CHECK(hana::make<hana::type_tag>(hana::type_c<X>) == hana::type_c<X>);
BOOST_HANA_CONSTANT_CHECK(hana::make_type(X{}) == hana::type_c<X>);
BOOST_HANA_CONSTANT_CHECK(hana::make_type(hana::type_c<X>) == hana::type_c<X>);
int main() { }
template<typename T >
constexpr auto make_type = hana::make<type_tag>
related

Equivalent to make<type_tag>, provided for convenience.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
struct X { };
BOOST_HANA_CONSTANT_CHECK(hana::make<hana::type_tag>(X{}) == hana::type_c<X>);
BOOST_HANA_CONSTANT_CHECK(hana::make<hana::type_tag>(hana::type_c<X>) == hana::type_c<X>);
BOOST_HANA_CONSTANT_CHECK(hana::make_type(X{}) == hana::type_c<X>);
BOOST_HANA_CONSTANT_CHECK(hana::make_type(hana::type_c<X>) == hana::type_c<X>);
int main() { }
template<typename T >
constexpr auto sizeof_
related
Initial value:
= [](auto&& x) {
using T = typename decltype(hana::decltype_(x))::type;
return hana::size_c<sizeof(T)>;
}

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

sizeof_(expr) == size_t<sizeof(decltype(expr) with references stripped)>

However, given a type, sizeof_ will simply fetch the size of the C++ type represented by that object. In other words,

sizeof_(type_c<T>) == size_t<sizeof(T)>

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_.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
struct X { };
static_assert(hana::sizeof_(hana::type_c<X>) == sizeof(X), "");
static_assert(hana::sizeof_(1) == sizeof(1), "");
static_assert(hana::sizeof_(hana::type_c<int>) == sizeof(int), "");
int main() {}
template<typename T >
constexpr auto alignof_
related
Initial value:
= [](auto&& x) {
using T = typename decltype(hana::decltype_(x))::type;
return hana::size_c<alignof(T)>;
}

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

alignof_(expr) == size_t<alignof(decltype(expr) with references stripped)>
alignof_(type_c<T>) == size_t<alignof(T)>

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_.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
namespace hana = boost::hana;
struct X { };
static_assert(hana::alignof_(hana::type_c<X>) == alignof(X), "");
static_assert(hana::alignof_(1) == alignof(decltype(1)), "");
static_assert(hana::alignof_(hana::type_c<int>) == alignof(int), "");
int main() { }
template<typename T >
constexpr auto is_valid
related
Initial value:
= [](auto&& f) {
return [](auto&& ...args) {
return whether f(args...) is a valid expression;
};
}

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...,

is_valid(f, args...) == whether f(args...) is valid

The result is returned as a compile-time Logical. Furthermore, is_valid can be used in curried form as follows:

is_valid(f)(args...)

This syntax makes it easy to create functions that check the validity of a generic expression on any given argument(s).

Warning
To check whether calling a nullary function 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.

Example

// Copyright Louis Dionne 2013-2017
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
#include <string>
#include <vector>
namespace hana = boost::hana;
int main() {
// Checking for a member
struct Person { std::string name; };
auto has_name = hana::is_valid([](auto&& p) -> decltype((void)p.name) { });
Person joe{"Joe"};
static_assert(has_name(joe), "");
static_assert(!has_name(1), "");
// Checking for a nested type
auto has_value_type = hana::is_valid([](auto t) -> hana::type<
typename decltype(t)::type::value_type
> { });
static_assert(has_value_type(hana::type_c<std::vector<int>>), "");
static_assert(!has_value_type(hana::type_c<Person>), "");
}