/*! @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 #include BOOST_HANA_NAMESPACE_BEGIN //! Base class of `hana::type`; used for pattern-matching. //! @relates hana::type //! //! Example //! ------- //! @include example/type/basic_type.cpp template 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` 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 //! void f(hana::basic_type) { //! // 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{} == hana::type{}` 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, type_c); //! 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, type_c); //! 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 struct type { //! Returns rvalue of self. //! See @ref type_lvalues_and_rvalues "description". constexpr auto operator+() const; //! Equivalent to `hana::equal` template friend constexpr auto operator==(X&& x, Y&& y); //! Equivalent to `hana::not_equal` template friend constexpr auto operator!=(X&& x, Y&& y); }; #else template struct type_impl; template using type = typename type_impl::_; #endif //! Tag representing `hana::type`. //! @relates hana::type struct type_tag { }; //! Creates an object representing the C++ type `T`. //! @relates hana::type template constexpr type 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 //! @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) == type_c //! @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)>` with this //! utility, because `decltype_(type_c)` would be just `type_c` //! instead of `type_c)>`. 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(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 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 //! @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) == type_c //! @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 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 = hana::decltype_; #endif //! Equivalent to `make`, provided for convenience. //! @relates hana::type //! //! //! Example //! ------- //! @include example/type/make.cpp constexpr auto make_type = hana::make; //! `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 //! @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) == size_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; }; #else struct sizeof_t { template 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_(type_c) == size_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; }; #else struct alignof_t { template 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 constexpr auto operator()(F&&) const; template 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_` is a //! `Metafunction` satisfying //! @code //! template_(type_c...) == type_c> //! decltype(template_)::apply::type == f //! @endcode //! //! @note //! In a SFINAE context, the expression `template_(type_c...)` is //! valid whenever the expression `f` is valid. //! //! //! Example //! ------- //! @include example/type/template.cpp #ifdef BOOST_HANA_DOXYGEN_INVOKED template