Micro template library A library for building device drivers
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 

355 Zeilen
11 KiB

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