/*! * \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 . */ #ifndef __utl_meta_invoke_h__ #define __utl_meta_invoke_h__ #include #include #include #include #include /*! * \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 struct identity { #if defined (UTL_WORKAROUND_CWG_1558) // decltype via use_() using Ts... to set the apply type template using _dummy = void_t; using apply = _Tp; //!< identity is invokable, must also have apply #else template using apply = _Tp; //!< identity is invokable, must also have apply #endif using type = _Tp; //!< identity }; //! identity type alias template using identity_t = type_>; //! @} //! Is evaluable trait //! @{ namespace detail { // we check for template \p F to be a metafunction with parameters \p T template class F, typename... T> struct is_evaluable_ { template class G, typename = G> static true_ check (int); template class> static false_ check (...); using type = decltype(check(0)); }; // we check for template \p F with integral constant parameters \p Is of type \p T // template class F, T... Is> // struct is_evaluable_i_ { // template class G, class = G> // static true_ check (int); // template class> // static false_ check (...); // // using type = decltype(check(0)); // }; } template class F, typename... T> using is_evaluable = type_< detail::is_evaluable_ >; // template class F, T... Is> // using is_evaluable_i = type_>>; //! @} //! defer //! @{ namespace detail { //! @{ template class F, typename... Ts> struct defer_ { using type = F; }; // template class F, T... Is> // struct defer_i_ { // using type = F; // }; //! //! We use struct instead of: //! template class F, typename... Ts> //! using defer_ = F; //! //! 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 template class F, class... Ts> using defer = if_< is_evaluable, detail::defer_, nil_ >; //! defer_i alias template for F // template class F, T... Is> // using defer_i = if_ < // is_evaluable_i>, // detail::defer_i_, // nil_ // >; //! @} /*! * quote is a higher-order primitive that wraps an n-ary Metafunction * to create a corresponding Metafunction Class (Invocable). */ template