Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-15 09:53:05

0001 /*!
0002 @file
0003 Forward declares `boost::hana::type` and related utilities.
0004 
0005 Copyright Louis Dionne 2013-2022
0006 Distributed under the Boost Software License, Version 1.0.
0007 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
0008  */
0009 
0010 #ifndef BOOST_HANA_FWD_TYPE_HPP
0011 #define BOOST_HANA_FWD_TYPE_HPP
0012 
0013 #include <boost/hana/config.hpp>
0014 #include <boost/hana/fwd/core/make.hpp>
0015 
0016 
0017 namespace boost { namespace hana {
0018     //! Base class of `hana::type`; used for pattern-matching.
0019     //! @relates hana::type
0020     //!
0021     //! Example
0022     //! -------
0023     //! @include example/type/basic_type.cpp
0024     template <typename T>
0025     struct basic_type;
0026 
0027     //! @ingroup group-datatypes
0028     //! C++ type in value-level representation.
0029     //!
0030     //! A `type` is a special kind of object representing a C++ type like
0031     //! `int`, `void`, `std::vector<float>` or anything else you can imagine.
0032     //!
0033     //! This page explains how `type`s work at a low level. To gain
0034     //! intuition about type-level metaprogramming in Hana, you should
0035     //! read the [tutorial section](@ref tutorial-type) on type-level
0036     //! computations.
0037     //!
0038     //!
0039     //! @note
0040     //! For subtle reasons, the actual representation of `hana::type` is
0041     //! implementation-defined. In particular, `hana::type` may be a dependent
0042     //! type, so one should not attempt to do pattern matching on it. However,
0043     //! one can assume that `hana::type` _inherits_ from `hana::basic_type`,
0044     //! which can be useful when declaring overloaded functions:
0045     //! @code
0046     //!     template <typename T>
0047     //!     void f(hana::basic_type<T>) {
0048     //!         // do something with T
0049     //!     }
0050     //! @endcode
0051     //! The full story is that [ADL][] causes template arguments to be
0052     //! instantiated. Hence, if `hana::type` were defined naively, expressions
0053     //! like `hana::type<T>{} == hana::type<U>{}` would cause both `T` and `U`
0054     //! to be instantiated. This is usually not a problem, except when `T` or
0055     //! `U` should not be instantiated. To avoid these instantiations,
0056     //! `hana::type` is implemented using some cleverness, and that is
0057     //! why the representation is implementation-defined. When that
0058     //! behavior is not required, `hana::basic_type` can be used instead.
0059     //!
0060     //!
0061     //! @anchor type_lvalues_and_rvalues
0062     //! Lvalues and rvalues
0063     //! -------------------
0064     //! When storing `type`s in heterogeneous containers, some algorithms
0065     //! will return references to those objects. Since we are primarily
0066     //! interested in accessing their nested `::%type`, receiving a reference
0067     //! is undesirable; we would end up trying to fetch the nested `::%type`
0068     //! inside a reference type, which is a compilation error:
0069     //! @code
0070     //!   auto ts = make_tuple(type_c<int>, type_c<char>);
0071     //!   using T = decltype(ts[0_c])::type; // error: 'ts[0_c]' is a reference!
0072     //! @endcode
0073     //!
0074     //! For this reason, `type`s provide an overload of the unary `+`
0075     //! operator that can be used to turn a lvalue into a rvalue. So when
0076     //! using a result which might be a reference to a `type` object, one
0077     //! can use `+` to make sure a rvalue is obtained before fetching its
0078     //! nested `::%type`:
0079     //! @code
0080     //!   auto ts = make_tuple(type_c<int>, type_c<char>);
0081     //!   using T = decltype(+ts[0_c])::type; // ok: '+ts[0_c]' is an rvalue
0082     //! @endcode
0083     //!
0084     //!
0085     //! Modeled concepts
0086     //! ----------------
0087     //! 1. `Comparable`\n
0088     //! Two types are equal if and only if they represent the same C++ type.
0089     //! Hence, equality is equivalent to the `std::is_same` type trait.
0090     //! @include example/type/comparable.cpp
0091     //!
0092     //! 2. `Hashable`\n
0093     //! The hash of a type is just that type itself. In other words, `hash`
0094     //! is the identity function on `hana::type`s.
0095     //! @include example/type/hashable.cpp
0096     //!
0097     //! [ADL]: http://en.cppreference.com/w/cpp/language/adl
0098 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0099     template <typename T>
0100     struct type {
0101         //! Returns rvalue of self.
0102         //! See @ref type_lvalues_and_rvalues "description".
0103         constexpr auto operator+() const;
0104 
0105         //! Equivalent to `hana::equal`
0106         template <typename X, typename Y>
0107         friend constexpr auto operator==(X&& x, Y&& y);
0108 
0109         //! Equivalent to `hana::not_equal`
0110         template <typename X, typename Y>
0111         friend constexpr auto operator!=(X&& x, Y&& y);
0112     };
0113 #else
0114     template <typename T>
0115     struct type_impl;
0116 
0117     template <typename T>
0118     using type = typename type_impl<T>::_;
0119 #endif
0120 
0121     //! Tag representing `hana::type`.
0122     //! @relates hana::type
0123     struct type_tag { };
0124 
0125     //! Creates an object representing the C++ type `T`.
0126     //! @relates hana::type
0127     template <typename T>
0128     BOOST_HANA_INLINE_VARIABLE constexpr type<T> type_c{};
0129 
0130     //! `decltype` keyword, lifted to Hana.
0131     //! @relates hana::type
0132     //!
0133     //! @deprecated
0134     //! The semantics of `decltype_` can be confusing, and `hana::typeid_`
0135     //! should be preferred instead. `decltype_` may be removed in the next
0136     //! major version of the library.
0137     //!
0138     //! `decltype_` is somewhat equivalent to `decltype` in that it returns
0139     //! the type of an object, except it returns it as a `hana::type` which
0140     //! is a first-class citizen of Hana instead of a raw C++ type.
0141     //! Specifically, given an object `x`, `decltype_` satisfies
0142     //! @code
0143     //!   decltype_(x) == type_c<decltype(x) with references stripped>
0144     //! @endcode
0145     //!
0146     //! As you can see, `decltype_` will strip any reference from the
0147     //! object's actual type. The reason for doing so is explained below.
0148     //! However, any `cv`-qualifiers will be retained. Also, when given a
0149     //! `hana::type`, `decltype_` is just the identity function. Hence,
0150     //! for any C++ type `T`,
0151     //! @code
0152     //!   decltype_(type_c<T>) == type_c<T>
0153     //! @endcode
0154     //!
0155     //! In conjunction with the way `metafunction` & al. are specified, this
0156     //! behavior makes it easier to interact with both types and values at
0157     //! the same time. However, it does make it impossible to create a `type`
0158     //! containing another `type` with `decltype_`. In other words, it is
0159     //! not possible to create a `type_c<decltype(type_c<T>)>` with this
0160     //! utility, because `decltype_(type_c<T>)` would be just `type_c<T>`
0161     //! instead of `type_c<decltype(type_c<T>)>`. This use case is assumed
0162     //! to be rare and a hand-coded function can be used if this is needed.
0163     //!
0164     //!
0165     //! ### Rationale for stripping the references
0166     //! The rules for template argument deduction are such that a perfect
0167     //! solution that always matches `decltype` is impossible. Hence, we
0168     //! have to settle on a solution that's good and and consistent enough
0169     //! for our needs. One case where matching `decltype`'s behavior is
0170     //! impossible is when the argument is a plain, unparenthesized variable
0171     //! or function parameter. In that case, `decltype_`'s argument will be
0172     //! deduced as a reference to that variable, but `decltype` would have
0173     //! given us the actual type of that variable, without references. Also,
0174     //! given the current definition of `metafunction` & al., it would be
0175     //! mostly useless if `decltype_` could return a reference, because it
0176     //! is unlikely that `F` expects a reference in its simplest use case:
0177     //! @code
0178     //!   int i = 0;
0179     //!   auto result = metafunction<F>(i);
0180     //! @endcode
0181     //!
0182     //! Hence, always discarding references seems to be the least painful
0183     //! solution.
0184     //!
0185     //!
0186     //! Example
0187     //! -------
0188     //! @include example/type/decltype.cpp
0189 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0190     constexpr auto decltype_ = see documentation;
0191 #else
0192     struct decltype_t {
0193         template <typename T>
0194         constexpr auto operator()(T&&) const;
0195     };
0196 
0197     BOOST_HANA_INLINE_VARIABLE constexpr decltype_t decltype_{};
0198 #endif
0199 
0200     //! Returns a `hana::type` representing the type of a given object.
0201     //! @relates hana::type
0202     //!
0203     //! `hana::typeid_` is somewhat similar to `typeid` in that it returns
0204     //! something that represents the type of an object. However, what
0205     //! `typeid` returns represent the _runtime_ type of the object, while
0206     //! `hana::typeid_` returns the _static_ type of the object. Specifically,
0207     //! given an object `x`, `typeid_` satisfies
0208     //! @code
0209     //!   typeid_(x) == type_c<decltype(x) with ref and cv-qualifiers stripped>
0210     //! @endcode
0211     //!
0212     //! As you can see, `typeid_` strips any reference and cv-qualifier from
0213     //! the object's actual type. The reason for doing so is that it faithfully
0214     //! models how the language's `typeid` behaves with respect to reference
0215     //! and cv-qualifiers, and it also turns out to be the desirable behavior
0216     //! most of the time. Also, when given a `hana::type`, `typeid_` is just
0217     //! the identity function. Hence, for any C++ type `T`,
0218     //! @code
0219     //!   typeid_(type_c<T>) == type_c<T>
0220     //! @endcode
0221     //!
0222     //! In conjunction with the way `metafunction` & al. are specified, this
0223     //! behavior makes it easier to interact with both types and values at
0224     //! the same time. However, it does make it impossible to create a `type`
0225     //! containing another `type` using `typeid_`. This use case is assumed
0226     //! to be rare and a hand-coded function can be used if this is needed.
0227     //!
0228     //!
0229     //! Example
0230     //! -------
0231     //! @include example/type/typeid.cpp
0232 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0233     constexpr auto typeid_ = see documentation;
0234 #else
0235     struct typeid_t {
0236         template <typename T>
0237         constexpr auto operator()(T&&) const;
0238     };
0239 
0240     BOOST_HANA_INLINE_VARIABLE constexpr typeid_t typeid_{};
0241 #endif
0242 
0243 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0244     //! Equivalent to `decltype_`, provided for convenience.
0245     //! @relates hana::type
0246     //!
0247     //!
0248     //! Example
0249     //! -------
0250     //! @include example/type/make.cpp
0251     template <>
0252     constexpr auto make<type_tag> = hana::decltype_;
0253 #endif
0254 
0255     //! Equivalent to `make<type_tag>`, provided for convenience.
0256     //! @relates hana::type
0257     //!
0258     //!
0259     //! Example
0260     //! -------
0261     //! @include example/type/make.cpp
0262     BOOST_HANA_INLINE_VARIABLE constexpr auto make_type = hana::make<type_tag>;
0263 
0264     //! `sizeof` keyword, lifted to Hana.
0265     //! @relates hana::type
0266     //!
0267     //! `sizeof_` is somewhat equivalent to `sizeof` in that it returns the
0268     //! size of an expression or type, but it takes an arbitrary expression
0269     //! or a `hana::type` and returns its size as an `integral_constant`.
0270     //! Specifically, given an expression `expr`, `sizeof_` satisfies
0271     //! @code
0272     //!   sizeof_(expr) == size_t<sizeof(decltype(expr) with references stripped)>
0273     //! @endcode
0274     //!
0275     //! However, given a `type`, `sizeof_` will simply fetch the size
0276     //! of the C++ type represented by that object. In other words,
0277     //! @code
0278     //!   sizeof_(type_c<T>) == size_t<sizeof(T)>
0279     //! @endcode
0280     //!
0281     //! The behavior of `sizeof_` is consistent with that of `decltype_`.
0282     //! In particular, see `decltype_`'s documentation to understand why
0283     //! references are always stripped by `sizeof_`.
0284     //!
0285     //!
0286     //! Example
0287     //! -------
0288     //! @include example/type/sizeof.cpp
0289 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0290     constexpr auto sizeof_ = [](auto&& x) {
0291         using T = typename decltype(hana::decltype_(x))::type;
0292         return hana::size_c<sizeof(T)>;
0293     };
0294 #else
0295     struct sizeof_t {
0296         template <typename T>
0297         constexpr auto operator()(T&&) const;
0298     };
0299 
0300     BOOST_HANA_INLINE_VARIABLE constexpr sizeof_t sizeof_{};
0301 #endif
0302 
0303     //! `alignof` keyword, lifted to Hana.
0304     //! @relates hana::type
0305     //!
0306     //! `alignof_` is somewhat equivalent to `alignof` in that it returns the
0307     //! alignment required by any instance of a type, but it takes a `type`
0308     //! and returns its alignment as an `integral_constant`. Like `sizeof`
0309     //! which works for expressions and type-ids, `alignof_` can also be
0310     //! called on an arbitrary expression. Specifically, given an expression
0311     //! `expr` and a C++ type `T`, `alignof_` satisfies
0312     //! @code
0313     //!   alignof_(expr) == size_t<alignof(decltype(expr) with references stripped)>
0314     //!   alignof_(type_c<T>) == size_t<alignof(T)>
0315     //! @endcode
0316     //!
0317     //! The behavior of `alignof_` is consistent with that of `decltype_`.
0318     //! In particular, see `decltype_`'s documentation to understand why
0319     //! references are always stripped by `alignof_`.
0320     //!
0321     //!
0322     //! Example
0323     //! -------
0324     //! @include example/type/alignof.cpp
0325 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0326     constexpr auto alignof_ = [](auto&& x) {
0327         using T = typename decltype(hana::decltype_(x))::type;
0328         return hana::size_c<alignof(T)>;
0329     };
0330 #else
0331     struct alignof_t {
0332         template <typename T>
0333         constexpr auto operator()(T&&) const;
0334     };
0335 
0336     BOOST_HANA_INLINE_VARIABLE constexpr alignof_t alignof_{};
0337 #endif
0338 
0339     //! Checks whether a SFINAE-friendly expression is valid.
0340     //! @relates hana::type
0341     //!
0342     //! Given a SFINAE-friendly function, `is_valid` returns whether the
0343     //! function call is valid with the given arguments. Specifically, given
0344     //! a function `f` and arguments `args...`,
0345     //! @code
0346     //!   is_valid(f, args...) == whether f(args...) is valid
0347     //! @endcode
0348     //!
0349     //! The result is returned as a compile-time `Logical`. Furthermore,
0350     //! `is_valid` can be used in curried form as follows:
0351     //! @code
0352     //!   is_valid(f)(args...)
0353     //! @endcode
0354     //!
0355     //! This syntax makes it easy to create functions that check the validity
0356     //! of a generic expression on any given argument(s).
0357     //!
0358     //! @warning
0359     //! To check whether calling a nullary function `f` is valid, one should
0360     //! use the `is_valid(f)()` syntax. Indeed, `is_valid(f /* no args */)`
0361     //! will be interpreted as the currying of `is_valid` to `f` rather than
0362     //! the application of `is_valid` to `f` and no arguments.
0363     //!
0364     //!
0365     //! Example
0366     //! -------
0367     //! @include example/type/is_valid.cpp
0368 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0369     constexpr auto is_valid = [](auto&& f) {
0370         return [](auto&& ...args) {
0371             return whether f(args...) is a valid expression;
0372         };
0373     };
0374 #else
0375     struct is_valid_t {
0376         template <typename F>
0377         constexpr auto operator()(F&&) const;
0378 
0379         template <typename F, typename ...Args>
0380         constexpr auto operator()(F&&, Args&&...) const;
0381     };
0382 
0383     BOOST_HANA_INLINE_VARIABLE constexpr is_valid_t is_valid{};
0384 #endif
0385 
0386     //! Lift a template to a Metafunction.
0387     //! @ingroup group-Metafunction
0388     //!
0389     //! Given a template class or template alias `f`, `template_<f>` is a
0390     //! `Metafunction` satisfying
0391     //! @code
0392     //!     template_<f>(type_c<x>...) == type_c<f<x...>>
0393     //!     decltype(template_<f>)::apply<x...>::type == f<x...>
0394     //! @endcode
0395     //!
0396     //! @note
0397     //! In a SFINAE context, the expression `template_<f>(type_c<x>...)` is
0398     //! valid whenever the expression `f<x...>` is valid.
0399     //!
0400     //!
0401     //! Example
0402     //! -------
0403     //! @include example/type/template.cpp
0404 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0405     template <template <typename ...> class F>
0406     constexpr auto template_ = [](basic_type<T>...) {
0407         return hana::type_c<F<T...>>;
0408     };
0409 #else
0410     template <template <typename ...> class F>
0411     struct template_t;
0412 
0413     template <template <typename ...> class F>
0414     BOOST_HANA_INLINE_VARIABLE constexpr template_t<F> template_{};
0415 #endif
0416 
0417     //! Lift a MPL-style metafunction to a Metafunction.
0418     //! @ingroup group-Metafunction
0419     //!
0420     //! Given a MPL-style metafunction, `metafunction<f>` is a `Metafunction`
0421     //! satisfying
0422     //! @code
0423     //!     metafunction<f>(type_c<x>...) == type_c<f<x...>::type>
0424     //!     decltype(metafunction<f>)::apply<x...>::type == f<x...>::type
0425     //! @endcode
0426     //!
0427     //! @note
0428     //! In a SFINAE context, the expression `metafunction<f>(type_c<x>...)` is
0429     //! valid whenever the expression `f<x...>::%type` is valid.
0430     //!
0431     //!
0432     //! Example
0433     //! -------
0434     //! @include example/type/metafunction.cpp
0435 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0436     template <template <typename ...> class F>
0437     constexpr auto metafunction = [](basic_type<T>...) {
0438         return hana::type_c<typename F<T...>::type>;
0439     };
0440 #else
0441     template <template <typename ...> class f>
0442     struct metafunction_t;
0443 
0444     template <template <typename ...> class f>
0445     BOOST_HANA_INLINE_VARIABLE constexpr metafunction_t<f> metafunction{};
0446 #endif
0447 
0448     //! Lift a MPL-style metafunction class to a Metafunction.
0449     //! @ingroup group-Metafunction
0450     //!
0451     //! Given a MPL-style metafunction class, `metafunction_class<f>` is a
0452     //! `Metafunction` satisfying
0453     //! @code
0454     //!     metafunction_class<f>(type_c<x>...) == type_c<f::apply<x...>::type>
0455     //!     decltype(metafunction_class<f>)::apply<x...>::type == f::apply<x...>::type
0456     //! @endcode
0457     //!
0458     //! @note
0459     //! In a SFINAE context, the expression `metafunction_class<f>(type_c<x>...)`
0460     //! is valid whenever the expression `f::apply<x...>::%type` is valid.
0461     //!
0462     //!
0463     //! Example
0464     //! -------
0465     //! @include example/type/metafunction_class.cpp
0466 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0467     template <typename F>
0468     constexpr auto metafunction_class = [](basic_type<T>...) {
0469         return hana::type_c<typename F::template apply<T...>::type>;
0470     };
0471 #else
0472     template <typename F>
0473     struct metafunction_class_t;
0474 
0475     template <typename F>
0476     BOOST_HANA_INLINE_VARIABLE constexpr metafunction_class_t<F> metafunction_class{};
0477 #endif
0478 
0479     //! Turn a `Metafunction` into a function taking `type`s and returning a
0480     //! default-constructed object.
0481     //! @ingroup group-Metafunction
0482     //!
0483     //! Given a `Metafunction` `f`, `integral` returns a new `Metafunction`
0484     //! that default-constructs an object of the type returned by `f`. More
0485     //! specifically, the following holds:
0486     //! @code
0487     //!     integral(f)(t...) == decltype(f(t...))::type{}
0488     //! @endcode
0489     //!
0490     //! The principal use case for `integral` is to transform `Metafunction`s
0491     //! returning a type that inherits from a meaningful base like
0492     //! `std::integral_constant` into functions returning e.g. a
0493     //! `hana::integral_constant`.
0494     //!
0495     //! @note
0496     //! - This is not a `Metafunction` because it does not return a `type`.
0497     //!   As such, it would not make sense to make `decltype(integral(f))`
0498     //!   a MPL metafunction class like the usual `Metafunction`s are.
0499     //!
0500     //! - When using `integral` with metafunctions returning
0501     //!   `std::integral_constant`s, don't forget to include the
0502     //!   boost/hana/ext/std/integral_constant.hpp header to ensure
0503     //!   Hana can interoperate with the result.
0504     //!
0505     //! - In a SFINAE context, the expression `integral(f)(t...)` is valid
0506     //!   whenever the expression `decltype(f(t...))::%type` is valid.
0507     //!
0508     //!
0509     //! Example
0510     //! -------
0511     //! @include example/type/integral.cpp
0512 #ifdef BOOST_HANA_DOXYGEN_INVOKED
0513     constexpr auto integral = [](auto f) {
0514         return [](basic_type<T>...) {
0515             return decltype(f)::apply<T...>::type{};
0516         };
0517     };
0518 #else
0519     template <typename F>
0520     struct integral_t;
0521 
0522     struct make_integral_t {
0523         template <typename F>
0524         constexpr integral_t<F> operator()(F const&) const
0525         { return {}; }
0526     };
0527 
0528     BOOST_HANA_INLINE_VARIABLE constexpr make_integral_t integral{};
0529 #endif
0530 
0531     //! Alias to `integral(metafunction<F>)`, provided for convenience.
0532     //! @ingroup group-Metafunction
0533     //!
0534     //!
0535     //! Example
0536     //! -------
0537     //! @include example/type/trait.cpp
0538     template <template <typename ...> class F>
0539     BOOST_HANA_INLINE_VARIABLE constexpr auto trait = hana::integral(hana::metafunction<F>);
0540 }} // end namespace boost::hana
0541 
0542 #endif // !BOOST_HANA_FWD_TYPE_HPP