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.
 
 
 
 

369 lignes
12 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/detection.h>
  25. #include <utl/meta/operations.h>
  26. /*!
  27. * \ingroup meta
  28. * \defgroup invoke
  29. *
  30. */
  31. //! @{
  32. namespace utl {
  33. namespace meta{
  34. /*!
  35. * \name meta::invoke
  36. *
  37. * A meta-programming invoke() analogous. A \c meta::invocable shall contain a nested
  38. * template type named \b apply which is bind to actual invocable meta-function.
  39. *
  40. * - We can use \c wrap<> or even better \c quote<> in order to wrap a metafunction to a type (metafunction class)
  41. * - We can pass these wrapped types to other metafunctions
  42. * - We can \c invoke<> the inner \c apply from a wrapped metafunction class.
  43. */
  44. //! @{
  45. /*!
  46. * identity, identity_t.
  47. */
  48. //! @{
  49. template <typename _Tp>
  50. struct identity {
  51. #if defined (UTL_WORKAROUND_CWG_1558)
  52. // redirect unused Ts... via void_t
  53. template <typename... Ts>
  54. using apply = first_of<_Tp, void_t<Ts...>>; //!< identity is invokable, must also have apply
  55. #else
  56. template <typename...>
  57. using apply = _Tp; //!< identity is invokable, must also have apply
  58. #endif
  59. using type = _Tp; //!< identity
  60. };
  61. //! identity type alias
  62. template <typename _Tp>
  63. using identity_t = eval<identity<_Tp>>;
  64. //! @}
  65. /*!
  66. * invoke, invoke_t
  67. */
  68. //! @{
  69. /*!
  70. * Invoke the nested apply meta-function from \c Fn with the arguments \c Args.
  71. * \note
  72. * This is an analogous to the std::invoke()
  73. */
  74. template <typename Fn, typename... Args>
  75. using invoke = typename Fn::template apply<Args...>;
  76. /*!
  77. * Evaluate the invocation of the nested apply metafunction from \p Fn
  78. * with the arguments \p Args.
  79. */
  80. template <typename Fn, typename... Args>
  81. using invoke_t = eval< invoke <Fn, Args...>>;
  82. //! @}
  83. //! wrap
  84. //! @{
  85. /*!
  86. * wrap is a higher-order primitive that wraps an n-ary Metafunction
  87. * to create a corresponding Metafunction Class (Invocable). This way
  88. * we can pass Metafunctions as types to other metafunctions and let
  89. * them \c invoke the inner templated apply
  90. */
  91. template <template <typename...> class F>
  92. struct wrap {
  93. template <typename... Args>
  94. using apply = F<Args...>;
  95. };
  96. //! Wrap a template \p F taking literal constants of type \p T into an Invokable
  97. template <typename T, template <T...> class F>
  98. struct wrap_i {
  99. // requires meta::Integral
  100. template <typename... Ts>
  101. using apply = F<Ts::type::value...>;
  102. };
  103. //! @}
  104. //! Is applicable trait
  105. //! @{
  106. namespace detail {
  107. template<template<typename...> class F, typename... T>
  108. struct is_applicable_ {
  109. template<template<typename...> class G, typename = G<T...>>
  110. static true_ check (int); //< T.. can be passed to G
  111. template<template<typename...> class>
  112. static false_ check (...); //< all other combinations
  113. using type = decltype(check<F>(0));
  114. };
  115. template<typename F, typename... T>
  116. struct is_applicable_q_ {
  117. template<typename G, typename Ret = invoke_t<G, T...>>
  118. static Ret check (int); //< T.. can be passed to G
  119. template<typename...>
  120. static nil_ check (...); //< all other combinations
  121. using type = if_ <
  122. not_same_<
  123. nil_,
  124. decltype(check<F>(0))
  125. >, true_, false_
  126. >;
  127. //!\note
  128. //! check doesn't return \c true_ or \c false_. The reason is that the \p F is
  129. //! probably quoted/deferred. This implies an embedded is_applicable<> check
  130. //! inside defer<> and so its guaranteed to be well formed.
  131. //! Thus we return the actual evaluated type and make the check for nil_
  132. };
  133. template<typename T, template <T...> class F, T... Is>
  134. struct is_applicable_i_ {
  135. template<typename TT, template<TT...> class G, typename = G<Is...>>
  136. static true_ check (int); //< Is... can be passed to G
  137. template<typename TT, template<TT...> class G>
  138. static false_ check (...); //< all other combinations
  139. using type = decltype(check<T, F>(0));
  140. };
  141. }
  142. //! check if we can instantiate \p F with parameters \p T
  143. template<template<typename...> class F, typename... T>
  144. using is_applicable_t = eval<
  145. detail::is_applicable_<F, T...>
  146. >;
  147. //! check if we can invoke \p Q with parameters \p T
  148. template<typename Q, typename... T>
  149. using is_applicable_qt = eval <
  150. detail::is_applicable_q_ <Q, T...>
  151. >;
  152. //! check if we can instantiate \p F with parameters \p Is of type \p T
  153. template <typename T, template<T...> class F, T... Is>
  154. using is_applicable_it = eval<
  155. detail::is_applicable_i_<T, F, Is...>
  156. >;
  157. //! @}
  158. //! defer
  159. //! @{
  160. namespace detail {
  161. //! @{
  162. template<template<typename...> class F, typename... Ts>
  163. struct defer_ {
  164. using type = F<Ts...>;
  165. };
  166. template<typename T, template<T...> class F, T... Is>
  167. struct defer_i_ {
  168. using type = F<Is...>;
  169. };
  170. //! \note
  171. //! We use struct instead of:
  172. //! template<template<typename...> class F, typename... Ts>
  173. //! using defer_ = F<Ts...>;
  174. //!
  175. //! The use of struct here is due to Core issue 1430 [\ref link1 1] and is used
  176. //! as suggested by Roy Crihfield in [\ref link2 2].
  177. //! In short, this is due to language's inability to expand Ts... into
  178. //! a fixed parameter list of an alias template.
  179. //!
  180. //! \anchor link1 [1]: https://wg21.link/cwg1430
  181. //! \anchor link2 [2]: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
  182. //! @}
  183. }
  184. //! defer alias template for F<Ts...>
  185. template<template<class...> class F, class... Ts>
  186. using defer = if_<
  187. detail::is_applicable_<F, Ts...>,
  188. detail::defer_<F, Ts...>,
  189. nil_ //!< Safe, nil_ is dereferencable
  190. >;
  191. //! defer_i alias template for F<T, Is...>
  192. template <typename T, template<T...> class F, T... Is>
  193. using defer_i = if_ <
  194. detail::is_applicable_i_<T, F, Is...>,
  195. detail::defer_i_<T, F, Is...>,
  196. nil_ //!< Safe, nil_ is dereferencable
  197. >;
  198. //! @}
  199. //! quote
  200. //! @{
  201. /*!
  202. * quote deferred is a higher-order primitive that wraps an n-ary Metafunction
  203. * to create a corresponding Metafunction Class (Invocable) using defer<> to
  204. * postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.
  205. * Again this way we can pass Metafunctions as types to other metafunctions and let
  206. * them \c invoke the inner templated apply
  207. */
  208. template <template <typename...> class F>
  209. struct quote {
  210. template <typename... Args>
  211. using apply = eval<
  212. defer<F, Args...> //!< defer here to avoid DR1430
  213. >;
  214. };
  215. //! Wrap a template \p F taking literal constants of type \p T into an Invokable
  216. template <typename T, template <T...> class F>
  217. struct quote_i {
  218. // requires meta::Integral
  219. template <typename... Ts>
  220. using apply = eval<
  221. defer_i<T, F, Ts::type::value...> //!< defer here to avoid DR1430
  222. >;
  223. };
  224. //! @}
  225. //! compose
  226. //! @{
  227. namespace detail {
  228. template <template <typename...> class... Fns> struct compose_f_ {};
  229. // recursive call to all invokes
  230. template <template <typename...> class Fn0,
  231. template <typename...> class... Fns>
  232. struct compose_f_<Fn0, Fns...> {
  233. template <typename... Args>
  234. using apply = invoke<
  235. quote<Fn0>,
  236. invoke<compose_f_<Fns...>, Args...>
  237. >;
  238. };
  239. // Termination specialization, finally pass the arguments
  240. template <template <typename...> class Fn0>
  241. struct compose_f_<Fn0> {
  242. template <typename ...Args>
  243. using apply = invoke<quote<Fn0>, Args...>;
  244. };
  245. template<typename ...Fns> struct compose_ {};
  246. // recursive call to all invokes
  247. template<typename Fn0, typename ...Fns>
  248. struct compose_<Fn0, Fns...> {
  249. template <typename ...Args>
  250. using apply = invoke<
  251. Fn0,
  252. invoke<compose_<Fns...>, Args...>
  253. >;
  254. };
  255. // Termination specialization, finally pass the arguments
  256. template<typename Fn0>
  257. struct compose_<Fn0> {
  258. template <typename... Args>
  259. using apply = invoke<Fn0, Args...>;
  260. };
  261. }
  262. /*!
  263. * Create an invocable from other invocables(quoted metafunctions) by composition.
  264. * \note
  265. * This implies from N invocables in \p Fns the first N-1 has to be unary.
  266. * Thats because of the "return" type of metafunction. They can only return one
  267. * type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
  268. * \example
  269. * \code
  270. * static_assert( std::is_same<
  271. * invoke<compose<quote<F1>, quote<F2>, quote<F3>>, int>, F1<F2<F3<int>>>
  272. * >, "");
  273. * \endcode
  274. */
  275. template <typename... Fns>
  276. using compose = detail::compose_<Fns...>;
  277. /*!
  278. * Create an invocable from other metafunctions by composition.
  279. * \note
  280. * This implies from N invocables in \p Fns the first N-1 has to be unary.
  281. * Thats because of the "return" type of metafunction. They can only return one
  282. * type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
  283. * \example
  284. * \code
  285. * static_assert( std::is_same<
  286. * invoke<compose_f<F1, F2, F3>, int>, F1 <F2 <F3 <int>>>
  287. * >, "");
  288. * \endcode
  289. */
  290. template <template <typename...> class... Fns>
  291. using compose_f = detail::compose_f_<Fns...>;
  292. //! @}
  293. /*!
  294. * Applies the invocable \p Fn by binding the arguments \p Ts
  295. * to the front of \p Fn.
  296. */
  297. template<typename Fn, typename... Ts>
  298. struct bind_front {
  299. template<typename... Us>
  300. using apply = invoke<Fn, Ts..., Us...>;
  301. };
  302. /*!
  303. * Applies the Invocable \p Fn by binding the arguments \p Ts
  304. * to the back of \p Fn.
  305. */
  306. template<typename Fn, typename... Ts>
  307. struct bind_back {
  308. template<typename... Us>
  309. using apply = invoke<Fn, Us..., Ts...>;
  310. };
  311. /*
  312. * ========== meta:: predicates ============
  313. */
  314. template <typename T1>
  315. struct same_as {
  316. template <typename T2>
  317. struct apply : same_<T1, T2> { };
  318. };
  319. template <typename T1>
  320. struct not_same_as {
  321. template <typename T2>
  322. struct apply : not_same_<T1, T2> { };
  323. };
  324. }}
  325. //! @}
  326. //! @}
  327. #endif /* __utl_meta_invoke_h__ */