Micro template library A library for building device drivers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

248 lines
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__ */