|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435 |
- /*!
- * \file utl/meta/invoke.h
- * \brief Template meta-programming utilities for callables
- */
- #ifndef __utl_meta_invoke_h__
- #define __utl_meta_invoke_h__
-
- #include <utl/core/impl.h>
- #include <utl/meta/basic.h>
- #include <utl/meta/detection.h>
-
- /*!
- * \ingroup meta
- * \defgroup meta_invoke Invoke
- * A meta-programming invoke() analogous.
- *
- * This module provides <b>higher order</b> tools to meta. utl::meta's metafunctions inputs are types.
- * The metafunctions though are templates in the form of `template <typename...> class`.
- * So we can not pass metafunctions to other metafunctions. The utl::meta provides tools to wrap metafunctions
- * in a type. This way we create the concepts of:
- *
- * - <b>\c invocable</b> which is a type containing a metafunction inside.
- * - <b>\c evaluation</b> which is the way of unwrapping the metafunction inside the invocable type.
- *
- * In order to accomplish that, by convention, a \c meta::invocable shall contain a nested
- * template type named \c apply which is bind to actual invocable meta-function. Then we can:
- *
- * - Use \c wrap<> or even better \c quote<> in order to wrap a metafunction to a type (metafunction class)
- * - Pass these wrapped types to other metafunctions
- * - \c invoke<> the inner \c apply from a wrapped metafunction class.
- */
- //! @{
- namespace utl {
- namespace meta{
-
- /*!
- * \name identity implementation
- */
- //! @{
-
- //! Identity is a metafunction always return the input type
- template <typename Tp>
- struct identity {
- #if defined (UTL_WORKAROUND_CWG_1558)
- // redirect unused Ts... via void_t
- template <typename... Ts>
- using apply = first_of<Tp, void_t<Ts...>>; //!< identity is invokable, must also have apply
- #else
- template <typename...>
- using apply = Tp; //!< identity is invokable, must also have apply
- #endif
- using type = Tp; //!< identity
- };
-
- //! identity type alias
- template <typename Tp>
- using identity_t = eval<identity<Tp>>;
- //! @}
-
- /*!
- * \name invoke, invoke_t
- */
- //! @{
- /*!
- * Invoke the nested apply meta-function from \c Fn with the arguments \c Args.
- * \note
- * This is an analogous to the std::invoke()
- */
- template <typename Fn, typename... Args>
- using invoke = typename Fn::template apply<Args...>;
-
- /*!
- * Evaluate the invocation of the nested apply metafunction from \p Fn
- * with the arguments \p Args.
- */
- template <typename Fn, typename... Args>
- using invoke_t = eval< invoke <Fn, Args...>>;
- //! @}
-
- //! \name wrap
- //! @{
-
- /*!
- * \brief
- * Wraps an n-ary Metafunction \c F to a Metafunction Class
- *
- * wrap is a higher-order primitive that wraps an n-ary Metafunction
- * to create a corresponding Metafunction Class (Invocable). This way
- * we can pass Metafunctions as types to other metafunctions and let
- * them \c invoke the inner templated apply.
- *
- * \tparam F The metafunction to wrap
- */
- template <template <typename...> class F>
- struct wrap {
- template <typename... Args>
- using apply = F<Args...>;
- };
-
- /*!
- * \brief
- * Wraps an n-ary Metafunction \c F taking literal constants of type \c T
- * to a Metafunction Class
- *
- * wrap_i is a higher-order primitive that wraps an n-ary Metafunction
- * to create a corresponding Metafunction Class (Invocable).
- * This way we can pass Metafunctions as types to other metafunctions and let
- * them \c invoke the inner templated apply.
- *
- * \tparam T Type of integral constants
- * \tparam F The metafunction to wrap
- */
- template <typename T, template <T...> class F>
- struct wrap_i {
- // requires meta::Integral
- template <typename... Ts>
- using apply = F<Ts::type::value...>;
- };
- //! @}
-
- //! \name Is applicable trait
- //! @{
- namespace details {
-
- template<template<typename...> class F, typename... T>
- struct is_applicable_ {
- template<template<typename...> class G, typename = G<T...>>
- static true_ check (int); //< T.. can be passed to G
- template<template<typename...> class>
- static false_ check (...); //< all other combinations
-
- using type = decltype(check<F>(0));
- };
-
- template<typename F, typename... T>
- struct is_applicable_q_ {
- template<typename G, typename Ret = invoke_t<G, T...>>
- static Ret check (int); //< T.. can be passed to G
- template<typename...>
- static nil_ check (...); //< all other combinations
-
- using type = if_ <
- not_same_<
- nil_,
- decltype(check<F>(0))
- >, true_, false_
- >;
- //!\note
- //! check doesn't return \c true_ or \c false_. The reason is that the \p F is
- //! probably quoted/deferred. This implies an embedded is_applicable<> check
- //! inside defer<> and so its guaranteed to be well formed.
- //! Thus we return the actual evaluated type and make the check for nil_
- };
-
- template<typename T, template <T...> class F, T... Is>
- struct is_applicable_i_ {
- template<typename TT, template<TT...> class G, typename = G<Is...>>
- static true_ check (int); //< Is... can be passed to G
- template<typename TT, template<TT...> class G>
- static false_ check (...); //< all other combinations
-
- using type = decltype(check<T, F>(0));
- };
- }
-
- /*!
- * \brief
- * Check if we can instantiate metafunction \c F with parameters \p Ts
- *
- * \tparam F The metafunction
- * \tparam Ts The parameters to \c F
- */
- template<template<typename...> class F, typename... Ts>
- using is_applicable_t = eval<
- details::is_applicable_<F, Ts...>
- >;
-
-
- /*!
- * \brief
- * Check if we can invoke the quoted metafunction \c Q with parameters \p Ts
- *
- * \tparam Q The quoted metafunction
- * \tparam Ts The parameters to \c Q
- *
- * \sa utl::meta::quote
- */
- template<typename Q, typename... Ts>
- using is_applicable_qt = eval <
- details::is_applicable_q_ <Q, Ts...>
- >;
-
- /*!
- * \brief
- * Check if we can instantiate metafunction \c F with parameters \p Is of type \c T
- *
- * \tparam T The type of \c Is
- * \tparam F The metafunction
- * \tparam Is The parameters to \c F
- */
- template <typename T, template<T...> class F, T... Is>
- using is_applicable_it = eval<
- details::is_applicable_i_<T, F, Is...>
- >;
-
- //! @}
-
- //! \name defer
- //! @{
- namespace details {
- template<template<typename...> class F, typename... Ts>
- struct defer_ {
- using type = F<Ts...>;
- };
-
- template<typename T, template<T...> class F, T... Is>
- struct defer_i_ {
- using type = F<Is...>;
- };
-
- //! \note
- //! We use struct instead of:
- //! template<template<typename...> class F, typename... Ts>
- //! using defer_ = F<Ts...>;
- //!
- //! The use of struct here is due to Core issue 1430 [1] and is used
- //! as suggested by Roy Crihfield in [2].
- //! In short, this is due to language's inability to expand Ts... into
- //! a fixed parameter list of an alias template.
- //!
- //! [1] https://wg21.link/cwg1430\n
- //! [2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
- }
-
- /*!
- * \brief
- * Postpone the instantiation of a metafunction \c F with parameters \c Ts
- *
- * This metafunction first checks if the given arguments \c Ts are applicable to
- * the metafunction \c F and if so nest inside (a layer deeper) the <em>metafunction call</em>.
- *
- * \tparam F The metafunction
- * \tparam Ts The parameters (arguments) to \c F
- */
- template<template<class...> class F, class... Ts>
- using defer = if_<
- details::is_applicable_<F, Ts...>,
- details::defer_<F, Ts...>,
- nil_ //!< Safe, nil_ is dereferencable
- >;
-
- /*!
- * \brief
- * Postpone the instantiation of a metafunction \c F with parameters \c Is of type \c T.
- *
- * This metafunction first checks if the given arguments \c Is of type \c T are applicable to
- * the metafunction \c F and if so nest inside (a layer deeper) the <em>metafunction call</em>.
- *
- * \tparam T The type of parameters
- * \tparam F The metafunction
- * \tparam Is The parameters (arguments) to \c F
- */
- template <typename T, template<T...> class F, T... Is>
- using defer_i = if_ <
- details::is_applicable_i_<T, F, Is...>,
- details::defer_i_<T, F, Is...>,
- nil_ //!< Safe, nil_ is dereferencable
- >;
- //! @}
-
- //! \name quote
- //! @{
- /*!
- * \brief
- * Wraps an n-ary Metafunction \c F to a Metafunction Class using meta::defer<>
- *
- * quote is a higher-order primitive that wraps an n-ary Metafunction
- * to create a corresponding Metafunction Class (Invocable) using defer<> to
- * postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.\n
- * Again this way we can pass Metafunctions as types to other metafunctions and let
- * them \c invoke the inner templated apply
- *
- * \tparam F The metafunction to wrap
- */
- template <template <typename...> class F>
- struct quote {
- template <typename... Args>
- using apply = eval<
- defer<F, Args...> //!< defer here to avoid DR1430
- >;
- };
-
-
- /*!
- * \brief
- * Wraps an n-ary Metafunction \c F taking literal constants of type \c T
- * to a Metafunction Class using meta::defer<>
- *
- * quote is a higher-order primitive that wraps an n-ary Metafunction
- * to create a corresponding Metafunction Class (Invocable) using defer<> to
- * postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.\n
- * Again this way we can pass Metafunctions as types to other metafunctions and let
- * them \c invoke the inner templated apply
- *
- * \tparam T Type of integral constants
- * \tparam F The metafunction to wrap
- */
- template <typename T, template <T...> class F>
- struct quote_i {
- // requires meta::Integral
- template <typename... Ts>
- using apply = eval<
- defer_i<T, F, Ts::type::value...> //!< defer here to avoid DR1430
- >;
- };
- //! @}
-
- //! \name compose
- //! @{
- namespace details {
- template <template <typename...> class... Fns> struct compose_f_ {};
-
- // recursive call to all invokes
- template <template <typename...> class Fn0,
- template <typename...> class... Fns>
- struct compose_f_<Fn0, Fns...> {
- template <typename... Args>
- using apply = invoke<
- quote<Fn0>,
- invoke<compose_f_<Fns...>, Args...>
- >;
- };
- // Termination specialization, finally pass the arguments
- template <template <typename...> class Fn0>
- struct compose_f_<Fn0> {
- template <typename ...Args>
- using apply = invoke<quote<Fn0>, Args...>;
- };
-
-
- template<typename ...Fns> struct compose_ {};
-
- // recursive call to all invokes
- template<typename Fn0, typename ...Fns>
- struct compose_<Fn0, Fns...> {
- template <typename ...Args>
- using apply = invoke<
- Fn0,
- invoke<compose_<Fns...>, Args...>
- >;
- };
- // Termination specialization, finally pass the arguments
- template<typename Fn0>
- struct compose_<Fn0> {
- template <typename... Args>
- using apply = invoke<Fn0, Args...>;
- };
- }
-
- /*!
- * \brief
- * Create an invocable from other invocables(quoted metafunctions) by composition.
- * \note
- * This implies from N invocables in \p Fns the first N-1 has to be unary.
- * Thats because of the "return" type of metafunction. They can only return one
- * type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
- *
- * \code
- * static_assert( std::is_same<
- * invoke<compose<quote<F1>, quote<F2>, quote<F3>>, int>, F1<F2<F3<int>>>
- * >, "");
- * \endcode
- */
- template <typename... Fns>
- using compose = details::compose_<Fns...>;
-
- /*!
- * \brief
- * Create an invocable from other metafunctions by composition.
- * \note
- * This implies from N invocables in \p Fns the first N-1 has to be unary.
- * Thats because of the "return" type of metafunction. They can only return one
- * type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
- *
- * \code
- * static_assert( std::is_same<
- * invoke<compose_f<F1, F2, F3>, int>, F1 <F2 <F3 <int>>>
- * >, "");
- * \endcode
- */
- template <template <typename...> class... Fns>
- using compose_f = details::compose_f_<Fns...>;
- //! @}
-
- /*!
- * \brief
- * Applies the invocable \p Fn by binding the arguments \p Ts to the front of \p Fn.
- */
- template<typename Fn, typename... Ts>
- struct bind_front {
- template<typename... Us>
- using apply = invoke<Fn, Ts..., Us...>;
- };
-
- /*!
- * \brief
- * Applies the Invocable \p Fn by binding the arguments \p Ts to the back of \p Fn.
- */
- template<typename Fn, typename... Ts>
- struct bind_back {
- template<typename... Us>
- using apply = invoke<Fn, Us..., Ts...>;
- };
-
-
- /*
- * ========== meta:: predicates ============
- */
- template <typename T1>
- struct same_as {
- template <typename T2>
- struct apply : same_<T1, T2> { };
- };
-
- template <typename T1>
- struct not_same_as {
- template <typename T2>
- struct apply : not_same_<T1, T2> { };
- };
-
- }}
-
- //! @}
-
- #endif /* __utl_meta_invoke_h__ */
|