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.
 
 
 
 

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