boost/hana/type.hpp
/*!
@file
Defines `boost::hana::type` and related utilities.
@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)
*/
#ifndef BOOST_HANA_TYPE_HPP
#define BOOST_HANA_TYPE_HPP
#include <boost/hana/fwd/type.hpp>
#include <boost/hana/bool.hpp>
#include <boost/hana/config.hpp>
#include <boost/hana/core/when.hpp>
#include <boost/hana/detail/operators/adl.hpp>
#include <boost/hana/detail/operators/comparable.hpp>
#include <boost/hana/fwd/concept/metafunction.hpp>
#include <boost/hana/fwd/core/make.hpp>
#include <boost/hana/fwd/equal.hpp>
#include <boost/hana/fwd/hash.hpp>
#include <boost/hana/integral_constant.hpp>
#include <type_traits>
#include <utility>
BOOST_HANA_NAMESPACE_BEGIN
//////////////////////////////////////////////////////////////////////////
// basic_type
//////////////////////////////////////////////////////////////////////////
//! @cond
template <typename T>
struct basic_type : detail::operators::adl<basic_type<T>> {
using hana_tag = type_tag;
using type = T;
constexpr auto operator+() const { return *this; }
};
//! @endcond
//////////////////////////////////////////////////////////////////////////
// type
//////////////////////////////////////////////////////////////////////////
template <typename T>
struct type_impl {
struct _ : basic_type<T> { };
};
//////////////////////////////////////////////////////////////////////////
// decltype_
//////////////////////////////////////////////////////////////////////////
namespace detail {
template <typename T, typename = type_tag>
struct decltype_t {
using type = typename std::remove_reference<T>::type;
};
template <typename T>
struct decltype_t<T, typename hana::tag_of<T>::type> {
using type = typename std::remove_reference<T>::type::type;
};
}
//! @cond
template <typename T>
constexpr auto decltype_t::operator()(T&&) const
{ return hana::type_c<typename detail::decltype_t<T>::type>; }
//! @endcond
//////////////////////////////////////////////////////////////////////////
// typeid_
//////////////////////////////////////////////////////////////////////////
namespace detail {
template <typename T, typename = type_tag>
struct typeid_t {
using type = typename std::remove_cv<
typename std::remove_reference<T>::type
>::type;
};
template <typename T>
struct typeid_t<T, typename hana::tag_of<T>::type> {
using type = typename std::remove_reference<T>::type::type;
};
}
//! @cond
template <typename T>
constexpr auto typeid_t::operator()(T&&) const
{ return hana::type_c<typename detail::typeid_t<T>::type>; }
//! @endcond
//////////////////////////////////////////////////////////////////////////
// make<type_tag>
//////////////////////////////////////////////////////////////////////////
template <>
struct make_impl<type_tag> {
template <typename T>
static constexpr auto apply(T&& t)
{ return hana::typeid_(static_cast<T&&>(t)); }
};
//////////////////////////////////////////////////////////////////////////
// sizeof_
//////////////////////////////////////////////////////////////////////////
//! @cond
template <typename T>
constexpr auto sizeof_t::operator()(T&&) const
{ return hana::size_c<sizeof(typename detail::decltype_t<T>::type)>; }
//! @endcond
//////////////////////////////////////////////////////////////////////////
// alignof_
//////////////////////////////////////////////////////////////////////////
//! @cond
template <typename T>
constexpr auto alignof_t::operator()(T&&) const
{ return hana::size_c<alignof(typename detail::decltype_t<T>::type)>; }
//! @endcond
//////////////////////////////////////////////////////////////////////////
// is_valid
//////////////////////////////////////////////////////////////////////////
namespace type_detail {
template <typename F, typename ...Args, typename = decltype(
std::declval<F&&>()(std::declval<Args&&>()...)
)>
constexpr auto is_valid_impl(int) { return hana::true_c; }
template <typename F, typename ...Args>
constexpr auto is_valid_impl(...) { return hana::false_c; }
template <typename F>
struct is_valid_fun {
template <typename ...Args>
constexpr auto operator()(Args&& ...) const
{ return is_valid_impl<F, Args&&...>(int{}); }
};
}
//! @cond
template <typename F>
constexpr auto is_valid_t::operator()(F&&) const
{ return type_detail::is_valid_fun<F&&>{}; }
template <typename F, typename ...Args>
constexpr auto is_valid_t::operator()(F&&, Args&& ...) const
{ return type_detail::is_valid_impl<F&&, Args&&...>(int{}); }
//! @endcond
//////////////////////////////////////////////////////////////////////////
// template_
//////////////////////////////////////////////////////////////////////////
// Note: We have to use the very complicated trick below instead of just
// mentionning `F<T...>` in a SFINAE-able context because of CWG 1430
// (http://www.open-std.org/Jtc1/sc22/wg21/docs/cwg_active.html#1430).
namespace template_detail {
template <typename ...T> struct args;
template <typename ...> using always_void = void;
template <template <typename ...> class F, typename Args, typename = void>
struct specialization_is_valid
: std::false_type
{ };
template <template <typename ...> class F, typename ...T>
struct specialization_is_valid<F, args<T...>, always_void<F<T...>>>
: std::true_type
{ };
} // end namespace detail
template <template <typename ...> class F>
struct template_t {
template <typename ...T>
struct apply {
using type = F<T...>;
};
template <typename ...T, typename = std::enable_if_t<
template_detail::specialization_is_valid<F, template_detail::args<typename T::type...>>::value
>>
constexpr auto operator()(T const& ...) const
{ return hana::type<F<typename T::type...>>{}; }
};
//////////////////////////////////////////////////////////////////////////
// metafunction
//////////////////////////////////////////////////////////////////////////
template <template <typename ...> class F>
struct metafunction_t {
template <typename ...T>
using apply = F<T...>;
template <typename ...T>
constexpr hana::type<typename F<typename T::type...>::type>
operator()(T const& ...) const { return {}; }
};
//////////////////////////////////////////////////////////////////////////
// metafunction_class
//////////////////////////////////////////////////////////////////////////
namespace detail {
template <typename F, typename ...T>
struct always_first { using type = F; };
}
template <typename F>
struct metafunction_class_t {
template <typename ...T>
using apply = typename detail::always_first<F, T...>::type::template apply<T...>;
template <typename ...T>
constexpr hana::type<typename detail::always_first<F, T...>::type::template apply<typename T::type...>::type>
operator()(T const& ...) const { return {}; }
};
//////////////////////////////////////////////////////////////////////////
// Metafunction
//////////////////////////////////////////////////////////////////////////
template <template <typename ...> class F>
struct Metafunction<template_t<F>> {
static constexpr bool value = true;
};
template <template <typename ...> class F>
struct Metafunction<metafunction_t<F>> {
static constexpr bool value = true;
};
template <typename F>
struct Metafunction<metafunction_class_t<F>> {
static constexpr bool value = true;
};
//////////////////////////////////////////////////////////////////////////
// integral
//////////////////////////////////////////////////////////////////////////
template <typename F>
struct integral_t {
template <typename ...T, typename Result =
typename detail::always_first<F, T...>::type::template apply<typename T::type...>::type
>
constexpr Result operator()(T const& ...) const {
return Result{};
}
};
//////////////////////////////////////////////////////////////////////////
// Operators
//////////////////////////////////////////////////////////////////////////
namespace detail {
template <>
struct comparable_operators<type_tag> {
static constexpr bool value = true;
};
}
//////////////////////////////////////////////////////////////////////////
// Comparable
//////////////////////////////////////////////////////////////////////////
template <>
struct equal_impl<type_tag, type_tag> {
template <typename T, typename U>
static constexpr auto apply(basic_type<T> const&, basic_type<U> const&)
{ return hana::false_c; }
template <typename T>
static constexpr auto apply(basic_type<T> const&, basic_type<T> const&)
{ return hana::true_c; }
};
//////////////////////////////////////////////////////////////////////////
// Hashable
//////////////////////////////////////////////////////////////////////////
template <>
struct hash_impl<hana::type_tag> {
template <typename T>
static constexpr T apply(T const& t)
{ return t; }
};
BOOST_HANA_NAMESPACE_END
#endif // !BOOST_HANA_TYPE_HPP