|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247 |
- /*!
- * \file invoke.h
- * \brief Template meta-programming utilities
- *
- * Copyright (C) 2018 Christos Choutouridis
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #ifndef __utl_meta_invoke_h__
- #define __utl_meta_invoke_h__
-
- #include <utl/core/impl.h>
- #include <utl/meta/integral.h>
- #include <utl/meta/void.h>
- #include <utl/meta/selection.h>
- #include <utl/meta/logical.h>
-
- /*!
- * \ingroup meta
- * \defgroup invoke
- *
- */
- //! @{
- namespace utl {
- namespace meta{
-
- /*!
- *
- * \name invoke
- * All Metafunction classes shall contain apply, which is Metafunction
- *
- * Metafunction:
- * A metafunction is a class or a class template that represents a function invocable at compile-time.
- * An non-nullary metafunction is invoked by instantiating the class template with particular template
- * parameters (metafunction arguments). The result of the metafunction application is accessible
- * through the instantiation's nested type typedef.
- * All metafunction's arguments must be types (i.e. only type template parameters are allowed).
- * A metafunction can have a variable number of parameters.
- * A nullary metafunction is represented as a (template) class with a nested type typename member.
- *
- * Metafunction Class:
- * A metafunction class is a certain form of metafunction representation that enables higher-order
- * metaprogramming. More precisely, it's a class with a publicly-accessible nested Metafunction called
- * apply. Correspondingly, a metafunction class invocation is defined as invocation of its nested apply
- * metafunction.
- *
- * Concept here is `Invokable` (contains apply metafunction)
- */
- //! @{
-
- /*!
- * *invocable* identity, identity_t.
- */
- //! @{
- template <typename _Tp>
- struct identity {
- #if defined (UTL_WORKAROUND_CWG_1558)
- // decltype via use_() using Ts... to set the apply type
- template <typename... Ts>
- using _dummy = void_t<Ts...>;
- using apply = _Tp; //!< 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 = type_<identity<_Tp>>;
- //! @}
-
- //! Is evaluable trait
- //! @{
- namespace detail {
-
- // we check for template \p F to be a metafunction with parameters \p T
- template<template<typename...> class F, typename... T>
- struct is_evaluable_ {
- template<template<typename...> class G, typename = G<T...>>
- static true_ check (int);
- template<template<typename...> class>
- static false_ check (...);
-
- using type = decltype(check<F>(0));
- };
-
- // we check for template \p F with integral constant parameters \p Is of type \p T
- // template<typename T, template <T...> class F, T... Is>
- // struct is_evaluable_i_ {
- // template<typename TT, template <TT...> class G, class = G<Is...>>
- // static true_ check (int);
- // template<typename, template<typename...> class>
- // static false_ check (...);
- //
- // using type = decltype(check<T, F>(0));
- // };
- }
-
- template<template<typename...> class F, typename... T>
- using is_evaluable = type_<
- detail::is_evaluable_<F, T...>
- >;
-
- // template <typename T, template<T...> class F, T... Is>
- // using is_evaluable_i = type_<detail::is_evaluable_i_<T, F<Is...>>>;
-
- //! @}
-
- //! defer
- //! @{
- namespace detail {
- //! @{
- 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...>;
- // };
- //!
- //! 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
- //! [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
- //! @}
- }
-
- //! defer alias template for F<Ts...>
- template<template<class...> class F, class... Ts>
- using defer = if_<
- is_evaluable<F, Ts...>,
- detail::defer_<F, Ts...>,
- nil_
- >;
-
- //! defer_i alias template for F<T, Is...>
- // template <typename T, template<T...> class F, T... Is>
- // using defer_i = if_ <
- // is_evaluable_i<T, F<Is...>>,
- // detail::defer_i_<F, Is...>,
- // nil_
- // >;
- //! @}
-
- /*!
- * quote is a higher-order primitive that wraps an n-ary Metafunction
- * to create a corresponding Metafunction Class (Invocable).
- */
- template <template <typename...> class F>
- struct quote {
- template <typename... Args>
- using apply = type_<defer<F, Args...>>; //!< defer here to avoid DR1430
- };
-
- //! Wrap a template \p F taking literals of type \p T into an Invokable
- // template <typename T, template <T...> class F>
- // struct quote_i {
- // // requires meta::Integral
- // template <typename... Is>
- // using apply = type_<
- // defer_i<T, F, Is...> //!< defer here to avoid DR1430
- // >;
- // };
-
- /*!
- * Invoke the nested apply metafunction from \c Fn
- * with the arguments \c Args.
- * requires Invocable(Fn)
- */
- template <typename Fn, typename... Args>
- using invoke = typename Fn::template apply<Args...>;
-
- //! compose
- //! @{
- namespace detail {
- 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...>;
- };
- }
- /*!
- * Create an invokable from other invokables by composition
- * ex:
- * compose<Fns...> will result to something like F0<F1<F2<F3<...>>>>
- */
- template <typename... Fns>
- using compose = detail::compose_<Fns...>;
- //! @}
-
- //! Applies the Invocable \p Fn by binding the arguments \p Ts
- //! to the \e front of \p Fn.
- template<typename Fn, typename... Ts>
- struct bind_front {
- template<typename... Us>
- using apply = invoke<Fn, Ts..., Us...>;
- };
-
- //! Applies the Invocable \p Fn by binding the arguments \p Ts
- //! to the \e back of \p Fn.
- template<typename Fn, typename... Ts>
- struct bind_back {
- template<typename... Us>
- using apply = invoke<Fn, Us..., Ts...>;
- };
-
- //! @}
- }}
-
- //! @}
-
- #endif /* __utl_meta_utility_h__ */
|