|
- /*!
- * \file invoke.h
- * \brief Template meta-programming utilities for callables
- *
- * 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 detail.
- *
- * 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 meta:: invoke
- *
- * A meta-programming invoke() analogous. A meta:: `invocable` shall contain a nested
- * template type named `apply` which is bind to actual invocable meta-function.
- */
- //! @{
-
- /*!
- * *invocable* identity, identity_t.
- */
- //! @{
- 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>>;
- //! @}
-
- //! Is applicable trait
- //! @{
- namespace detail {
-
- 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 Fn, typename... Args>
- using use_ = typename Fn::template apply<Args...>;
-
- template<typename F, typename... T>
- struct is_applicable_q_ {
- template<typename G, typename Ret= eval<use_<G, T...>>>
- static Ret check (int); //< T.. can be passed to G
- template<typename...>
- static nil_ check (...); //< all other combinations
-
- using type = decltype(check<F>(0));
- };
-
- 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));
- };
- }
-
- //! check if we can instantiate \p F with parameters \p T
- template<template<typename...> class F, typename... T>
- using is_applicable_t = eval<
- detail::is_applicable_<F, T...>
- >;
- //! check if we can instantiate \p Q with parameters \p T and the instant
- //! is different from \c nil_
- template<typename Q, typename... T>
- using is_applicable_qt = eval <
- // Extra check for quoted metafunctions to check return type
- if_ <
- not_same_<
- eval <detail::is_applicable_q_ <Q, T...>>,
- nil_
- >,
- true_,
- false_
- >
- >;
- //! check if we can instantiate \p F with parameters \p Is of type \p T
- template <typename T, template<T...> class F, T... Is>
- using is_applicable_it = eval<
- detail::is_applicable_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...>;
- };
-
- //! \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
- //! [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_<
- detail::is_applicable_<F, Ts...>,
- detail::defer_<F, Ts...>,
- nil_ //!< This should be identity<nil_> if nil_ was empty
- >;
-
- //! defer_i alias template for F<T, Is...>
- template <typename T, template<T...> class F, T... Is>
- using defer_i = if_ <
- detail::is_applicable_i_<T, F, Is...>,
- detail::defer_i_<T, F, Is...>,
- nil_ //!< This should be identity<nil_> if nil_ was empty
- >;
- //! @}
-
- /*!
- * 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 = eval<
- 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... Ts>
- using apply = eval<
- defer_i<T, F, Ts::type::value...> //!< defer here to avoid DR1430
- >;
- };
-
- /*!
- * Invoke the nested apply meta-function from \c Fn
- * with the arguments \c Args.
- * \note
- * This is like 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...>>;
-
- //! 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 invocable from other invocables by composition.
- * \note
- * This implies from N invocables in \p Fns the first N-1 has to be unary.
- * That 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.
- * \example
- * \code
- * static_assert(std::is_same<
- * invoke<compose<F1, F2, F3>, int>,
- * F1 <F2 <F3 <int>>>
- * >, "" );
- * \endcode
- */
- template <typename... Fns>
- using compose = detail::compose_<Fns...>;
- //! @}
-
- /*!
- * 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...>;
- };
-
- /*!
- * 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__ */
|