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.
 
 
 
 

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