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.
 
 
 
 

299 lignes
8.9 KiB

  1. /*!
  2. * \file invoke.h
  3. * \brief Template meta-programming utilities for callables
  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 detail.
  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. * \name meta:: invoke
  37. *
  38. * A meta-programming invoke() analogous. A meta:: `invocable` shall contain a nested
  39. * template type named `apply` which is bind to actual invocable meta-function.
  40. */
  41. //! @{
  42. /*!
  43. * *invocable* identity, identity_t.
  44. */
  45. //! @{
  46. template <typename _Tp>
  47. struct identity {
  48. #if defined (UTL_WORKAROUND_CWG_1558)
  49. // redirect unused Ts... via void_t
  50. template <typename... Ts>
  51. using apply = first_of<_Tp, void_t<Ts...>>; //!< identity is invokable, must also have apply
  52. #else
  53. template <typename...>
  54. using apply = _Tp; //!< identity is invokable, must also have apply
  55. #endif
  56. using type = _Tp; //!< identity
  57. };
  58. //! identity type alias
  59. template <typename _Tp>
  60. using identity_t = eval<identity<_Tp>>;
  61. //! @}
  62. //! Is applicable trait
  63. //! @{
  64. namespace detail {
  65. template<template<typename...> class F, typename... T>
  66. struct is_applicable_ {
  67. template<template<typename...> class G, typename = G<T...>>
  68. static true_ check (int); //< T.. can be passed to G
  69. template<template<typename...> class>
  70. static false_ check (...); //< all other combinations
  71. using type = decltype(check<F>(0));
  72. };
  73. template <typename Fn, typename... Args>
  74. using use_ = typename Fn::template apply<Args...>;
  75. template<typename F, typename... T>
  76. struct is_applicable_q_ {
  77. template<typename G, typename Ret= eval<use_<G, T...>>>
  78. static Ret check (int); //< T.. can be passed to G
  79. template<typename...>
  80. static nil_ check (...); //< all other combinations
  81. using type = decltype(check<F>(0));
  82. };
  83. template<typename T, template <T...> class F, T... Is>
  84. struct is_applicable_i_ {
  85. template<typename TT, template<TT...> class G, typename =G<Is...>>
  86. static true_ check (int); //< Is... can be passed to G
  87. template<typename TT, template<TT...> class G>
  88. static false_ check (...); //< all other combinations
  89. using type = decltype(check<T, F>(0));
  90. };
  91. }
  92. //! check if we can instantiate \p F with parameters \p T
  93. template<template<typename...> class F, typename... T>
  94. using is_applicable_t = eval<
  95. detail::is_applicable_<F, T...>
  96. >;
  97. //! check if we can instantiate \p Q with parameters \p T and the instant
  98. //! is different from \c nil_
  99. template<typename Q, typename... T>
  100. using is_applicable_qt = eval <
  101. // Extra check for quoted metafunctions to check return type
  102. if_ <
  103. not_same_<
  104. eval <detail::is_applicable_q_ <Q, T...>>,
  105. nil_
  106. >,
  107. true_,
  108. false_
  109. >
  110. >;
  111. //! check if we can instantiate \p F with parameters \p Is of type \p T
  112. template <typename T, template<T...> class F, T... Is>
  113. using is_applicable_it = eval<
  114. detail::is_applicable_i_<T, F, Is...>
  115. >;
  116. //! @}
  117. //! defer
  118. //! @{
  119. namespace detail {
  120. //! @{
  121. template<template<typename...> class F, typename... Ts>
  122. struct defer_ {
  123. using type = F<Ts...>;
  124. };
  125. template<typename T, template<T...> class F, T... Is>
  126. struct defer_i_ {
  127. using type = F<Is...>;
  128. };
  129. //! \note
  130. //! We use struct instead of:
  131. //! template<template<typename...> class F, typename... Ts>
  132. //! using defer_ = F<Ts...>;
  133. //!
  134. //! The use of struct here is due to Core issue 1430 [1] and is used
  135. //! as suggested by Roy Crihfield in [2].
  136. //! In short, this is due to language's inability to expand Ts... into
  137. //! a fixed parameter list of an alias template.
  138. //!
  139. //! [1]: https://wg21.link/cwg1430
  140. //! [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
  141. //! @}
  142. }
  143. //! defer alias template for F<Ts...>
  144. template<template<class...> class F, class... Ts>
  145. using defer = if_<
  146. detail::is_applicable_<F, Ts...>,
  147. detail::defer_<F, Ts...>,
  148. nil_ //!< This should be identity<nil_> if nil_ was empty
  149. >;
  150. //! defer_i alias template for F<T, Is...>
  151. template <typename T, template<T...> class F, T... Is>
  152. using defer_i = if_ <
  153. detail::is_applicable_i_<T, F, Is...>,
  154. detail::defer_i_<T, F, Is...>,
  155. nil_ //!< This should be identity<nil_> if nil_ was empty
  156. >;
  157. //! @}
  158. /*!
  159. * quote is a higher-order primitive that wraps an n-ary Metafunction
  160. * to create a corresponding Metafunction Class (Invocable).
  161. */
  162. template <template <typename...> class F>
  163. struct quote {
  164. template <typename... Args>
  165. using apply = eval<
  166. defer<F, Args...> //!< defer here to avoid DR1430
  167. >;
  168. };
  169. //! Wrap a template \p F taking literals of type \p T into an Invokable
  170. template <typename T, template <T...> class F>
  171. struct quote_i {
  172. // requires meta::Integral
  173. template <typename... Ts>
  174. using apply = eval<
  175. defer_i<T, F, Ts::type::value...> //!< defer here to avoid DR1430
  176. >;
  177. };
  178. /*!
  179. * Invoke the nested apply meta-function from \c Fn
  180. * with the arguments \c Args.
  181. * \note
  182. * This is like the std::invoke()
  183. */
  184. template <typename Fn, typename... Args>
  185. using invoke = typename Fn::template apply<Args...>;
  186. /*!
  187. * Evaluate the invocation of the nested apply metafunction from \p Fn
  188. * with the arguments \p Args.
  189. */
  190. template <typename Fn, typename... Args>
  191. using invoke_t = eval< invoke <Fn, Args...>>;
  192. //! compose
  193. //! @{
  194. namespace detail {
  195. template<typename ...Fns> struct compose_ { };
  196. // recursive call to all invokes
  197. template<typename Fn0, typename ...Fns>
  198. struct compose_<Fn0, Fns...> {
  199. template <typename ...Args>
  200. using apply = invoke<
  201. Fn0,
  202. invoke<compose_<Fns...>, Args...>
  203. >;
  204. };
  205. // Termination specialization, finally pass the arguments
  206. template<typename Fn0>
  207. struct compose_<Fn0> {
  208. template <typename... Args>
  209. using apply = invoke<Fn0, Args...>;
  210. };
  211. }
  212. /*!
  213. * Create an invocable from other invocables by composition.
  214. * \note
  215. * This implies from N invocables in \p Fns the first N-1 has to be unary.
  216. * That because of the "return" type of metafunction. They can only return one
  217. * type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
  218. * \example
  219. * \code
  220. * static_assert(std::is_same<
  221. * invoke<compose<F1, F2, F3>, int>,
  222. * F1 <F2 <F3 <int>>>
  223. * >, "" );
  224. * \endcode
  225. */
  226. template <typename... Fns>
  227. using compose = detail::compose_<Fns...>;
  228. //! @}
  229. /*!
  230. * Applies the Invocable \p Fn by binding the arguments \p Ts
  231. * to the front of \p Fn.
  232. */
  233. template<typename Fn, typename... Ts>
  234. struct bind_front {
  235. template<typename... Us>
  236. using apply = invoke<Fn, Ts..., Us...>;
  237. };
  238. /*!
  239. * Applies the Invocable \p Fn by binding the arguments \p Ts
  240. * to the back of \p Fn.
  241. */
  242. template<typename Fn, typename... Ts>
  243. struct bind_back {
  244. template<typename... Us>
  245. using apply = invoke<Fn, Us..., Ts...>;
  246. };
  247. /*
  248. * ========== meta:: predicates ============
  249. */
  250. template <typename T1>
  251. struct same_as {
  252. template < typename T2>
  253. struct apply : same_<T1, T2> { };
  254. };
  255. template <typename T1>
  256. struct not_same_as {
  257. template < typename T2>
  258. struct apply : not_same_<T1, T2> { };
  259. };
  260. }}
  261. //! @}
  262. //! @}
  263. #endif /* __utl_meta_invoke_h__ */