Boost.Hana  1.0.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 having to do with ADL, 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
}

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-2016
    // 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-2016
    // 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...
 
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.

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-2016
// 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 >
template<>
constexpr auto make< type_tag > = hana::decltype_
related

Equivalent to decltype_, provided for convenience.

Example

// Copyright Louis Dionne 2013-2016
// 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-2016
// 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-2016
// 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-2016
// 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-2016
// 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>), "");
}