123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542 |
- /*!
- @file
- Forward declares `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_FWD_TYPE_HPP
- #define BOOST_HANA_FWD_TYPE_HPP
- #include <boost/hana/config.hpp>
- #include <boost/hana/fwd/core/make.hpp>
- BOOST_HANA_NAMESPACE_BEGIN
- //! Base class of `hana::type`; used for pattern-matching.
- //! @relates hana::type
- //!
- //! Example
- //! -------
- //! @include example/type/basic_type.cpp
- template <typename T>
- struct basic_type;
- //! @ingroup group-datatypes
- //! 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 `type`s work at a low level. To gain
- //! intuition about type-level metaprogramming in Hana, you should
- //! read the [tutorial section](@ref tutorial-type) 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:
- //! @code
- //! template <typename T>
- //! void f(hana::basic_type<T>) {
- //! // do something with T
- //! }
- //! @endcode
- //! 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.
- //!
- //!
- //! @anchor type_lvalues_and_rvalues
- //! Lvalues and rvalues
- //! -------------------
- //! When storing `type`s 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:
- //! @code
- //! auto ts = make_tuple(type_c<int>, type_c<char>);
- //! using T = decltype(ts[0_c])::type; // error: 'ts[0_c]' is a reference!
- //! @endcode
- //!
- //! For this reason, `type`s 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`:
- //! @code
- //! auto ts = make_tuple(type_c<int>, type_c<char>);
- //! using T = decltype(+ts[0_c])::type; // ok: '+ts[0_c]' is an rvalue
- //! @endcode
- //!
- //!
- //! Modeled concepts
- //! ----------------
- //! 1. `Comparable`\n
- //! 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.
- //! @include example/type/comparable.cpp
- //!
- //! 2. `Hashable`\n
- //! The hash of a type is just that type itself. In other words, `hash`
- //! is the identity function on `hana::type`s.
- //! @include example/type/hashable.cpp
- //!
- //! [ADL]: http://en.cppreference.com/w/cpp/language/adl
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- template <typename T>
- struct type {
- //! Returns rvalue of self.
- //! See @ref type_lvalues_and_rvalues "description".
- constexpr auto operator+() const;
- //! Equivalent to `hana::equal`
- template <typename X, typename Y>
- friend constexpr auto operator==(X&& x, Y&& y);
- //! Equivalent to `hana::not_equal`
- template <typename X, typename Y>
- friend constexpr auto operator!=(X&& x, Y&& y);
- };
- #else
- template <typename T>
- struct type_impl;
- template <typename T>
- using type = typename type_impl<T>::_;
- #endif
- //! Tag representing `hana::type`.
- //! @relates hana::type
- struct type_tag { };
- //! Creates an object representing the C++ type `T`.
- //! @relates hana::type
- template <typename T>
- constexpr type<T> type_c{};
- //! `decltype` keyword, lifted to Hana.
- //! @relates hana::type
- //!
- //! @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
- //! @code
- //! decltype_(x) == type_c<decltype(x) with references stripped>
- //! @endcode
- //!
- //! 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`,
- //! @code
- //! decltype_(type_c<T>) == type_c<T>
- //! @endcode
- //!
- //! 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:
- //! @code
- //! int i = 0;
- //! auto result = metafunction<F>(i);
- //! @endcode
- //!
- //! Hence, always discarding references seems to be the least painful
- //! solution.
- //!
- //!
- //! Example
- //! -------
- //! @include example/type/decltype.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- constexpr auto decltype_ = see documentation;
- #else
- struct decltype_t {
- template <typename T>
- constexpr auto operator()(T&&) const;
- };
- constexpr decltype_t decltype_{};
- #endif
- //! Returns a `hana::type` representing the type of a given object.
- //! @relates hana::type
- //!
- //! `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
- //! @code
- //! typeid_(x) == type_c<decltype(x) with ref and cv-qualifiers stripped>
- //! @endcode
- //!
- //! 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`,
- //! @code
- //! typeid_(type_c<T>) == type_c<T>
- //! @endcode
- //!
- //! 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
- //! -------
- //! @include example/type/typeid.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- constexpr auto typeid_ = see documentation;
- #else
- struct typeid_t {
- template <typename T>
- constexpr auto operator()(T&&) const;
- };
- constexpr typeid_t typeid_{};
- #endif
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- //! Equivalent to `decltype_`, provided for convenience.
- //! @relates hana::type
- //!
- //!
- //! Example
- //! -------
- //! @include example/type/make.cpp
- template <>
- constexpr auto make<type_tag> = hana::decltype_;
- #endif
- //! Equivalent to `make<type_tag>`, provided for convenience.
- //! @relates hana::type
- //!
- //!
- //! Example
- //! -------
- //! @include example/type/make.cpp
- constexpr auto make_type = hana::make<type_tag>;
- //! `sizeof` keyword, lifted to Hana.
- //! @relates hana::type
- //!
- //! `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
- //! @code
- //! sizeof_(expr) == size_t<sizeof(decltype(expr) with references stripped)>
- //! @endcode
- //!
- //! However, given a `type`, `sizeof_` will simply fetch the size
- //! of the C++ type represented by that object. In other words,
- //! @code
- //! sizeof_(type_c<T>) == size_t<sizeof(T)>
- //! @endcode
- //!
- //! 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
- //! -------
- //! @include example/type/sizeof.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- constexpr auto sizeof_ = [](auto&& x) {
- using T = typename decltype(hana::decltype_(x))::type;
- return hana::size_c<sizeof(T)>;
- };
- #else
- struct sizeof_t {
- template <typename T>
- constexpr auto operator()(T&&) const;
- };
- constexpr sizeof_t sizeof_{};
- #endif
- //! `alignof` keyword, lifted to Hana.
- //! @relates hana::type
- //!
- //! `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
- //! @code
- //! alignof_(expr) == size_t<alignof(decltype(expr) with references stripped)>
- //! alignof_(type_c<T>) == size_t<alignof(T)>
- //! @endcode
- //!
- //! 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
- //! -------
- //! @include example/type/alignof.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- constexpr auto alignof_ = [](auto&& x) {
- using T = typename decltype(hana::decltype_(x))::type;
- return hana::size_c<alignof(T)>;
- };
- #else
- struct alignof_t {
- template <typename T>
- constexpr auto operator()(T&&) const;
- };
- constexpr alignof_t alignof_{};
- #endif
- //! Checks whether a SFINAE-friendly expression is valid.
- //! @relates hana::type
- //!
- //! 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...`,
- //! @code
- //! is_valid(f, args...) == whether f(args...) is valid
- //! @endcode
- //!
- //! The result is returned as a compile-time `Logical`. Furthermore,
- //! `is_valid` can be used in curried form as follows:
- //! @code
- //! is_valid(f)(args...)
- //! @endcode
- //!
- //! 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
- //! -------
- //! @include example/type/is_valid.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- constexpr auto is_valid = [](auto&& f) {
- return [](auto&& ...args) {
- return whether f(args...) is a valid expression;
- };
- };
- #else
- struct is_valid_t {
- template <typename F>
- constexpr auto operator()(F&&) const;
- template <typename F, typename ...Args>
- constexpr auto operator()(F&&, Args&&...) const;
- };
- constexpr is_valid_t is_valid{};
- #endif
- //! Lift a template to a Metafunction.
- //! @ingroup group-Metafunction
- //!
- //! Given a template class or template alias `f`, `template_<f>` is a
- //! `Metafunction` satisfying
- //! @code
- //! template_<f>(type_c<x>...) == type_c<f<x...>>
- //! decltype(template_<f>)::apply<x...>::type == f<x...>
- //! @endcode
- //!
- //! @note
- //! In a SFINAE context, the expression `template_<f>(type_c<x>...)` is
- //! valid whenever the expression `f<x...>` is valid.
- //!
- //!
- //! Example
- //! -------
- //! @include example/type/template.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- template <template <typename ...> class F>
- constexpr auto template_ = [](basic_type<T>...) {
- return hana::type_c<F<T...>>;
- };
- #else
- template <template <typename ...> class F>
- struct template_t;
- template <template <typename ...> class F>
- constexpr template_t<F> template_{};
- #endif
- //! Lift a MPL-style metafunction to a Metafunction.
- //! @ingroup group-Metafunction
- //!
- //! Given a MPL-style metafunction, `metafunction<f>` is a `Metafunction`
- //! satisfying
- //! @code
- //! metafunction<f>(type_c<x>...) == type_c<f<x...>::type>
- //! decltype(metafunction<f>)::apply<x...>::type == f<x...>::type
- //! @endcode
- //!
- //! @note
- //! In a SFINAE context, the expression `metafunction<f>(type_c<x>...)` is
- //! valid whenever the expression `f<x...>::%type` is valid.
- //!
- //!
- //! Example
- //! -------
- //! @include example/type/metafunction.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- template <template <typename ...> class F>
- constexpr auto metafunction = [](basic_type<T>...) {
- return hana::type_c<typename F<T...>::type>;
- };
- #else
- template <template <typename ...> class f>
- struct metafunction_t;
- template <template <typename ...> class f>
- constexpr metafunction_t<f> metafunction{};
- #endif
- //! Lift a MPL-style metafunction class to a Metafunction.
- //! @ingroup group-Metafunction
- //!
- //! Given a MPL-style metafunction class, `metafunction_class<f>` is a
- //! `Metafunction` satisfying
- //! @code
- //! metafunction_class<f>(type_c<x>...) == type_c<f::apply<x...>::type>
- //! decltype(metafunction_class<f>)::apply<x...>::type == f::apply<x...>::type
- //! @endcode
- //!
- //! @note
- //! In a SFINAE context, the expression `metafunction_class<f>(type_c<x>...)`
- //! is valid whenever the expression `f::apply<x...>::%type` is valid.
- //!
- //!
- //! Example
- //! -------
- //! @include example/type/metafunction_class.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- template <typename F>
- constexpr auto metafunction_class = [](basic_type<T>...) {
- return hana::type_c<typename F::template apply<T...>::type>;
- };
- #else
- template <typename F>
- struct metafunction_class_t;
- template <typename F>
- constexpr metafunction_class_t<F> metafunction_class{};
- #endif
- //! Turn a `Metafunction` into a function taking `type`s and returning a
- //! default-constructed object.
- //! @ingroup group-Metafunction
- //!
- //! 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:
- //! @code
- //! integral(f)(t...) == decltype(f(t...))::type{}
- //! @endcode
- //!
- //! 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.
- //!
- //! - In a SFINAE context, the expression `integral(f)(t...)` is valid
- //! whenever the expression `decltype(f(t...))::%type` is valid.
- //!
- //!
- //! Example
- //! -------
- //! @include example/type/integral.cpp
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- constexpr auto integral = [](auto f) {
- return [](basic_type<T>...) {
- return decltype(f)::apply<T...>::type{};
- };
- };
- #else
- template <typename F>
- struct integral_t;
- struct make_integral_t {
- template <typename F>
- constexpr integral_t<F> operator()(F const&) const
- { return {}; }
- };
- constexpr make_integral_t integral{};
- #endif
- //! Alias to `integral(metafunction<F>)`, provided for convenience.
- //! @ingroup group-Metafunction
- //!
- //!
- //! Example
- //! -------
- //! @include example/type/trait.cpp
- template <template <typename ...> class F>
- constexpr auto trait = hana::integral(hana::metafunction<F>);
- BOOST_HANA_NAMESPACE_END
- #endif // !BOOST_HANA_FWD_TYPE_HPP
|