Boost.Hana: Metafunction

| Boost.Hana 1.0.0 Your standard library for metaprogramming |

Variables
Metafunction
Concepts

## Description

A `Metafunction` is a function that takes `hana::type`s as inputs and returns a `hana::type` as output.

A `Metafunction` is an object satisfying the FunctionObject concept, but with additional requirements. First, it must be possible to apply a `Metafunction` to arguments whose tag is `type_tag`, and the result of such an application must be an object whose tag is also `type_tag`. Note that `hana::type` and `hana::basic_type` are the only such types.

Secondly, a `Metafunction` must provide a nested `::apply` template which allows performing the same type-level computation as is done by the call operator. In Boost.MPL parlance, a `Metafunction` `F` is hence a MetafunctionClass in addition to being a `FunctionObject`. Rigorously, the following must be satisfied by any object `f` of type `F` which is a `Metafunction`, and for arbitrary types `T...`:

f(hana::type_c<T>...) == hana::type_c<F::apply<T...>::type>

Thirdly, to ease the inter-operation of values and types, `Metafunction`s must also allow being called with arguments that are not `hana::type`s. In that case, the result is equivalent to calling the metafunction on the types of the arguments. Rigorously, this means that for arbitrary objects `x...`,

f(x...) == f(hana::type_c<decltype(x)>...)

## Minimal complete definition

The `Metafunction` concept does not have a minimal complete definition in terms of tag-dispatched methods. Instead, the syntactic requirements documented above should be satisfied, and the `Metafunction` struct should be specialized explicitly in Hana's namespace.

## Concrete models

`hana::metafunction`, `hana::metafunction_class`, `hana::template_`

## Rationale: Why aren't `Metafunction`s `Comparable`?

When seeing `hana::template_`, a question that naturally arises is whether `Metafunction`s should be made `Comparable`. Indeed, it would seem to make sense to compare two templates `F` and `G` with `template_<F> == template_<G>`. However, in the case where `F` and/or `G` are alias templates, it makes sense to talk about two types of comparisons. The first one is shallow comparison, and it determines that two alias templates are equal if they are the same alias template. The second one is deep comparison, and it determines that two template aliases are equal if they alias the same type for any template argument. For example, given `F` and `G` defined as

template <typename T>
using F = void;
template <typename T>
using G = void;

shallow comparison would determine that `F` and `G` are different because they are two different template aliases, while deep comparison would determine that `F` and `G` are equal because they always expand to the same type, `void`. Unfortunately, deep comparison is impossible to implement because one would have to check `F` and `G` on all possible types. On the other hand, shallow comparison is not satisfactory because `Metafunction`s are nothing but functions on `type`s, and the equality of two functions is normally defined with deep comparison. Hence, we adopt a conservative stance and avoid providing comparison for `Metafunction`s.

## Variables
template<template< typename... > class F>
constexpr auto | boost::hana::template_
| Lift a template to a Metafunction.Given a template class or template alias `f`, `template_<f>` is a `Metafunction` satisfying. More...
template<template< typename... > class F>
constexpr auto | boost::hana::metafunction
| Lift a MPL-style metafunction to a Metafunction.Given a MPL-style metafunction, `metafunction<f>` is a `Metafunction` satisfying. More...
template<typename F >
constexpr auto | boost::hana::metafunction_class
| Lift a MPL-style metafunction class to a Metafunction.Given a MPL-style metafunction class, `metafunction_class<f>` is a `Metafunction` satisfying. More...
constexpr auto | boost::hana::integral
| Turn a `Metafunction` into a function taking `type`s and returning a default-constructed object.Given a `Metafunction` `f`, `integral` returns a new `Metafunction` that default-constructs an object of the type returned by `f`. More specifically, the following holds: More...
template<template< typename... > class F>
constexpr auto | boost::hana::trait = hana::integral(hana::metafunction<F>)
| Alias to `integral(metafunction<F>)`, provided for convenience. More...

## Variable Documentation

template<template< typename... > class F>

constexpr auto boost::hana::template_

`#include <boost/hana/fwd/type.hpp>`

Initial value:
= [](basic_type<T>-or-T ...) {
return hana::type_c<F<T...>>;
}

Lift a template to a Metafunction.Given a template class or template alias `f`, `template_<f>` is a `Metafunction` satisfying.

template_<f>(type_c<x>...) == type_c<f<x...>>
decltype(template_<f>)::apply<x...>::type == f<x...>

Note
  `template_` can't be SFINAE-friendly right now because of Core issue 1430.

## 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 <boost/hana/assert.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/type.hpp>
#include <type_traits>
namespace hana = boost::hana;
template <typename ...> struct f;
struct x;
struct y;
BOOST_HANA_CONSTANT_CHECK(hana::template_<f>() == hana::type_c<f<>>);
BOOST_HANA_CONSTANT_CHECK(hana::template_<f>(hana::type_c<x>) == hana::type_c<f<x>>);
BOOST_HANA_CONSTANT_CHECK(hana::template_<f>(hana::type_c<x>, hana::type_c<y>) == hana::type_c<f<x, y>>);
static_assert(std::is_same<
decltype(hana::template_<f>)::apply<x, y>::type,
f<x, y>
>::value, "");
int main() { }
template<template< typename... > class F>

constexpr auto boost::hana::metafunction

`#include <boost/hana/fwd/type.hpp>`

Initial value:
= [](basic_type<T>-or-T ...) {
return hana::type_c<typename F<T...>::type>;
}

Lift a MPL-style metafunction to a Metafunction.Given a MPL-style metafunction, `metafunction<f>` is a `Metafunction` satisfying.

metafunction<f>(type_c<x>...) == type_c<f<x...>::type>
decltype(metafunction<f>)::apply<x...>::type == f<x...>::type

## 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 <boost/hana/assert.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/type.hpp>
#include <type_traits>
namespace hana = boost::hana;
template <typename ...> struct f { struct type; };
struct x;
struct y;
BOOST_HANA_CONSTANT_CHECK(hana::metafunction<f>() == hana::type_c<f<>::type>);
BOOST_HANA_CONSTANT_CHECK(hana::metafunction<f>(hana::type_c<x>) == hana::type_c<f<x>::type>);
BOOST_HANA_CONSTANT_CHECK(hana::metafunction<f>(hana::type_c<x>, hana::type_c<y>) == hana::type_c<f<x, y>::type>);
static_assert(std::is_same<
decltype(hana::metafunction<f>)::apply<x, y>::type,
f<x, y>::type
>::value, "");
int main() { }
template<typename F >

constexpr auto boost::hana::metafunction_class

`#include <boost/hana/fwd/type.hpp>`

Initial value:
= [](basic_type<T>-or-T ...) {
return hana::type_c<typename F::template apply<T...>::type>;
}
boost::hana::apply
constexpr auto apply
Invokes a Callable with the given arguments.
Definition: apply.hpp:40

Lift a MPL-style metafunction class to a Metafunction.Given a MPL-style metafunction class, `metafunction_class<f>` is a `Metafunction` satisfying.

metafunction_class<f>(type_c<x>...) == type_c<f::apply<x...>::type>
decltype(metafunction_class<f>)::apply<x...>::type == f::apply<x...>::type

## 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 <boost/hana/assert.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/type.hpp>
#include <type_traits>
namespace hana = boost::hana;
struct f { template <typename ...> struct apply { struct type; }; };
struct x;
struct y;
BOOST_HANA_CONSTANT_CHECK(hana::metafunction_class<f>() == hana::type_c<f::apply<>::type>);
BOOST_HANA_CONSTANT_CHECK(hana::metafunction_class<f>(hana::type_c<x>) == hana::type_c<f::apply<x>::type>);
BOOST_HANA_CONSTANT_CHECK(hana::metafunction_class<f>(hana::type_c<x>, hana::type_c<y>) == hana::type_c<f::apply<x, y>::type>);
static_assert(std::is_same<
decltype(hana::metafunction_class<f>)::apply<x, y>::type,
f::apply<x, y>::type
>::value, "");
int main() { }

constexpr auto boost::hana::integral

`#include <boost/hana/fwd/type.hpp>`

Initial value:
= [](auto f) {
return [](basic_type<T>-or-T ...) {
return decltype(f)::apply<T...>::type{};
};
}
boost::hana::apply
constexpr auto apply
Invokes a Callable with the given arguments.
Definition: apply.hpp:40

Turn a `Metafunction` into a function taking `type`s and returning a default-constructed object.Given a `Metafunction` `f`, `integral` returns a new `Metafunction` that default-constructs an object of the type returned by `f`. More specifically, the following holds:

integral(f)(t...) == decltype(f(t...))::type{}

The principal use case for `integral` is to transform `Metafunction`s returning a type that inherits from a meaningful base like `std::integral_constant` into functions returning e.g. a `hana::integral_constant`.

Note
  - This is not a `Metafunction` because it does not return a `type`. As such, it would not make sense to make `decltype(integral(f))` a MPL metafunction class like the usual `Metafunction`s are.
  - When using `integral` with metafunctions returning `std::integral_constant`s, don't forget to include the boost/hana/ext/std/integral_constant.hpp header to ensure Hana can interoperate with the result.

## 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 <boost/hana/assert.hpp>
#include <boost/hana/ext/std/integral_constant.hpp>
#include <boost/hana/not.hpp>
#include <boost/hana/type.hpp>
#include <type_traits>
namespace hana = boost::hana;
constexpr auto is_void = hana::integral(hana::metafunction<std::is_void>);
BOOST_HANA_CONSTANT_CHECK(is_void(hana::type_c<void>));
BOOST_HANA_CONSTANT_CHECK(hana::not_(is_void(hana::type_c<int>)));
int main() { }
template<template< typename... > class F>

constexpr auto boost::hana::trait = hana::integral(hana::metafunction<F>)

`#include <boost/hana/fwd/type.hpp>`

Alias to `integral(metafunction<F>)`, 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)
#include <boost/hana/assert.hpp>
#include <boost/hana/ext/std/integral_constant.hpp>
#include <boost/hana/not.hpp>
#include <boost/hana/type.hpp>
#include <type_traits>
namespace hana = boost::hana;
BOOST_HANA_CONSTANT_CHECK(hana::trait<std::is_integral>(hana::type_c<int>));
BOOST_HANA_CONSTANT_CHECK(hana::not_(hana::trait<std::is_integral>(hana::type_c<float>)));
int main() { }