Micro template library A library for building device drivers
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 

248 lignes
7.9 KiB

  1. /*!
  2. * \file invoke.h
  3. * \brief Template meta-programming utilities
  4. *
  5. * Copyright (C) 2018 Christos Choutouridis
  6. *
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation, either version 3
  10. * of the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #ifndef __utl_meta_invoke_h__
  21. #define __utl_meta_invoke_h__
  22. #include <utl/core/impl.h>
  23. #include <utl/meta/integral.h>
  24. #include <utl/meta/void.h>
  25. #include <utl/meta/selection.h>
  26. #include <utl/meta/logical.h>
  27. /*!
  28. * \ingroup meta
  29. * \defgroup invoke
  30. *
  31. */
  32. //! @{
  33. namespace utl {
  34. namespace meta{
  35. /*!
  36. *
  37. * \name invoke
  38. * All Metafunction classes shall contain apply, which is Metafunction
  39. *
  40. * Metafunction:
  41. * A metafunction is a class or a class template that represents a function invocable at compile-time.
  42. * An non-nullary metafunction is invoked by instantiating the class template with particular template
  43. * parameters (metafunction arguments). The result of the metafunction application is accessible
  44. * through the instantiation's nested type typedef.
  45. * All metafunction's arguments must be types (i.e. only type template parameters are allowed).
  46. * A metafunction can have a variable number of parameters.
  47. * A nullary metafunction is represented as a (template) class with a nested type typename member.
  48. *
  49. * Metafunction Class:
  50. * A metafunction class is a certain form of metafunction representation that enables higher-order
  51. * metaprogramming. More precisely, it's a class with a publicly-accessible nested Metafunction called
  52. * apply. Correspondingly, a metafunction class invocation is defined as invocation of its nested apply
  53. * metafunction.
  54. *
  55. * Concept here is `Invokable` (contains apply metafunction)
  56. */
  57. //! @{
  58. /*!
  59. * *invocable* identity, identity_t.
  60. */
  61. //! @{
  62. template <typename _Tp>
  63. struct identity {
  64. #if defined (UTL_WORKAROUND_CWG_1558)
  65. // decltype via use_() using Ts... to set the apply type
  66. template <typename... Ts>
  67. using _dummy = void_t<Ts...>;
  68. using apply = _Tp; //!< identity is invokable, must also have apply
  69. #else
  70. template <typename...>
  71. using apply = _Tp; //!< identity is invokable, must also have apply
  72. #endif
  73. using type = _Tp; //!< identity
  74. };
  75. //! identity type alias
  76. template <typename _Tp>
  77. using identity_t = type_<identity<_Tp>>;
  78. //! @}
  79. //! Is evaluable trait
  80. //! @{
  81. namespace detail {
  82. // we check for template \p F to be a metafunction with parameters \p T
  83. template<template<typename...> class F, typename... T>
  84. struct is_evaluable_ {
  85. template<template<typename...> class G, typename = G<T...>>
  86. static true_ check (int);
  87. template<template<typename...> class>
  88. static false_ check (...);
  89. using type = decltype(check<F>(0));
  90. };
  91. // we check for template \p F with integral constant parameters \p Is of type \p T
  92. // template<typename T, template <T...> class F, T... Is>
  93. // struct is_evaluable_i_ {
  94. // template<typename TT, template <TT...> class G, class = G<Is...>>
  95. // static true_ check (int);
  96. // template<typename, template<typename...> class>
  97. // static false_ check (...);
  98. //
  99. // using type = decltype(check<T, F>(0));
  100. // };
  101. }
  102. template<template<typename...> class F, typename... T>
  103. using is_evaluable = type_<
  104. detail::is_evaluable_<F, T...>
  105. >;
  106. // template <typename T, template<T...> class F, T... Is>
  107. // using is_evaluable_i = type_<detail::is_evaluable_i_<T, F<Is...>>>;
  108. //! @}
  109. //! defer
  110. //! @{
  111. namespace detail {
  112. //! @{
  113. template<template<typename...> class F, typename... Ts>
  114. struct defer_ {
  115. using type = F<Ts...>;
  116. };
  117. // template<typename T, template<T...> class F, T... Is>
  118. // struct defer_i_ {
  119. // using type = F<Is...>;
  120. // };
  121. //!
  122. //! We use struct instead of:
  123. //! template<template<typename...> class F, typename... Ts>
  124. //! using defer_ = F<Ts...>;
  125. //!
  126. //! The use of struct here is due to Core issue 1430 [1] and is used
  127. //! as suggested by Roy Crihfield in [2].
  128. //! In short, this is due to language's inability to expand Ts... into
  129. //! a fixed parameter list of an alias template.
  130. //!
  131. //! [1]: https://wg21.link/cwg1430
  132. //! [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
  133. //! @}
  134. }
  135. //! defer alias template for F<Ts...>
  136. template<template<class...> class F, class... Ts>
  137. using defer = if_<
  138. is_evaluable<F, Ts...>,
  139. detail::defer_<F, Ts...>,
  140. nil_
  141. >;
  142. //! defer_i alias template for F<T, Is...>
  143. // template <typename T, template<T...> class F, T... Is>
  144. // using defer_i = if_ <
  145. // is_evaluable_i<T, F<Is...>>,
  146. // detail::defer_i_<F, Is...>,
  147. // nil_
  148. // >;
  149. //! @}
  150. /*!
  151. * quote is a higher-order primitive that wraps an n-ary Metafunction
  152. * to create a corresponding Metafunction Class (Invocable).
  153. */
  154. template <template <typename...> class F>
  155. struct quote {
  156. template <typename... Args>
  157. using apply = type_<defer<F, Args...>>; //!< defer here to avoid DR1430
  158. };
  159. //! Wrap a template \p F taking literals of type \p T into an Invokable
  160. // template <typename T, template <T...> class F>
  161. // struct quote_i {
  162. // // requires meta::Integral
  163. // template <typename... Is>
  164. // using apply = type_<
  165. // defer_i<T, F, Is...> //!< defer here to avoid DR1430
  166. // >;
  167. // };
  168. /*!
  169. * Invoke the nested apply metafunction from \c Fn
  170. * with the arguments \c Args.
  171. * requires Invocable(Fn)
  172. */
  173. template <typename Fn, typename... Args>
  174. using invoke = typename Fn::template apply<Args...>;
  175. //! compose
  176. //! @{
  177. namespace detail {
  178. template<typename ...Fns> struct compose_ { };
  179. // recursive call to all invokes
  180. template<typename Fn0, typename ...Fns>
  181. struct compose_<Fn0, Fns...> {
  182. template <typename ...Args>
  183. using apply = invoke<
  184. Fn0,
  185. invoke<compose_<Fns...>, Args...>
  186. >;
  187. };
  188. // Termination specialization, finally pass the arguments
  189. template<typename Fn0>
  190. struct compose_<Fn0> {
  191. template <typename... Args>
  192. using apply = invoke<Fn0, Args...>;
  193. };
  194. }
  195. /*!
  196. * Create an invokable from other invokables by composition
  197. * ex:
  198. * compose<Fns...> will result to something like F0<F1<F2<F3<...>>>>
  199. */
  200. template <typename... Fns>
  201. using compose = detail::compose_<Fns...>;
  202. //! @}
  203. //! Applies the Invocable \p Fn by binding the arguments \p Ts
  204. //! to the \e front of \p Fn.
  205. template<typename Fn, typename... Ts>
  206. struct bind_front {
  207. template<typename... Us>
  208. using apply = invoke<Fn, Ts..., Us...>;
  209. };
  210. //! Applies the Invocable \p Fn by binding the arguments \p Ts
  211. //! to the \e back of \p Fn.
  212. template<typename Fn, typename... Ts>
  213. struct bind_back {
  214. template<typename... Us>
  215. using apply = invoke<Fn, Us..., Ts...>;
  216. };
  217. //! @}
  218. }}
  219. //! @}
  220. #endif /* __utl_meta_utility_h__ */