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.
 
 
 
 

436 lignes
14 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 meta_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. * \brief
  76. * Wraps an n-ary Metafunction \c F to a Metafunction Class
  77. *
  78. * wrap is a higher-order primitive that wraps an n-ary Metafunction
  79. * to create a corresponding Metafunction Class (Invocable). This way
  80. * we can pass Metafunctions as types to other metafunctions and let
  81. * them \c invoke the inner templated apply.
  82. *
  83. * \tparam F The metafunction to wrap
  84. */
  85. template <template <typename...> class F>
  86. struct wrap {
  87. template <typename... Args>
  88. using apply = F<Args...>;
  89. };
  90. /*!
  91. * \brief
  92. * Wraps an n-ary Metafunction \c F taking literal constants of type \c T
  93. * to a Metafunction Class
  94. *
  95. * wrap_i is a higher-order primitive that wraps an n-ary Metafunction
  96. * to create a corresponding Metafunction Class (Invocable).
  97. * This way we can pass Metafunctions as types to other metafunctions and let
  98. * them \c invoke the inner templated apply.
  99. *
  100. * \tparam T Type of integral constants
  101. * \tparam F The metafunction to wrap
  102. */
  103. template <typename T, template <T...> class F>
  104. struct wrap_i {
  105. // requires meta::Integral
  106. template <typename... Ts>
  107. using apply = F<Ts::type::value...>;
  108. };
  109. //! @}
  110. //! \name Is applicable trait
  111. //! @{
  112. namespace details {
  113. template<template<typename...> class F, typename... T>
  114. struct is_applicable_ {
  115. template<template<typename...> class G, typename = G<T...>>
  116. static true_ check (int); //< T.. can be passed to G
  117. template<template<typename...> class>
  118. static false_ check (...); //< all other combinations
  119. using type = decltype(check<F>(0));
  120. };
  121. template<typename F, typename... T>
  122. struct is_applicable_q_ {
  123. template<typename G, typename Ret = invoke_t<G, T...>>
  124. static Ret check (int); //< T.. can be passed to G
  125. template<typename...>
  126. static nil_ check (...); //< all other combinations
  127. using type = if_ <
  128. not_same_<
  129. nil_,
  130. decltype(check<F>(0))
  131. >, true_, false_
  132. >;
  133. //!\note
  134. //! check doesn't return \c true_ or \c false_. The reason is that the \p F is
  135. //! probably quoted/deferred. This implies an embedded is_applicable<> check
  136. //! inside defer<> and so its guaranteed to be well formed.
  137. //! Thus we return the actual evaluated type and make the check for nil_
  138. };
  139. template<typename T, template <T...> class F, T... Is>
  140. struct is_applicable_i_ {
  141. template<typename TT, template<TT...> class G, typename = G<Is...>>
  142. static true_ check (int); //< Is... can be passed to G
  143. template<typename TT, template<TT...> class G>
  144. static false_ check (...); //< all other combinations
  145. using type = decltype(check<T, F>(0));
  146. };
  147. }
  148. /*!
  149. * \brief
  150. * Check if we can instantiate metafunction \c F with parameters \p Ts
  151. *
  152. * \tparam F The metafunction
  153. * \tparam Ts The parameters to \c F
  154. */
  155. template<template<typename...> class F, typename... Ts>
  156. using is_applicable_t = eval<
  157. details::is_applicable_<F, Ts...>
  158. >;
  159. /*!
  160. * \brief
  161. * Check if we can invoke the quoted metafunction \c Q with parameters \p Ts
  162. *
  163. * \tparam Q The quoted metafunction
  164. * \tparam Ts The parameters to \c Q
  165. *
  166. * \sa utl::meta::quote
  167. */
  168. template<typename Q, typename... Ts>
  169. using is_applicable_qt = eval <
  170. details::is_applicable_q_ <Q, Ts...>
  171. >;
  172. /*!
  173. * \brief
  174. * Check if we can instantiate metafunction \c F with parameters \p Is of type \c T
  175. *
  176. * \tparam T The type of \c Is
  177. * \tparam F The metafunction
  178. * \tparam Is The parameters to \c F
  179. */
  180. template <typename T, template<T...> class F, T... Is>
  181. using is_applicable_it = eval<
  182. details::is_applicable_i_<T, F, Is...>
  183. >;
  184. //! @}
  185. //! \name defer
  186. //! @{
  187. namespace details {
  188. template<template<typename...> class F, typename... Ts>
  189. struct defer_ {
  190. using type = F<Ts...>;
  191. };
  192. template<typename T, template<T...> class F, T... Is>
  193. struct defer_i_ {
  194. using type = F<Is...>;
  195. };
  196. //! \note
  197. //! We use struct instead of:
  198. //! template<template<typename...> class F, typename... Ts>
  199. //! using defer_ = F<Ts...>;
  200. //!
  201. //! The use of struct here is due to Core issue 1430 [1] and is used
  202. //! as suggested by Roy Crihfield in [2].
  203. //! In short, this is due to language's inability to expand Ts... into
  204. //! a fixed parameter list of an alias template.
  205. //!
  206. //! [1] https://wg21.link/cwg1430\n
  207. //! [2] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59498
  208. }
  209. /*!
  210. * \brief
  211. * Postpone the instantiation of a metafunction \c F with parameters \c Ts
  212. *
  213. * This metafunction first checks if the given arguments \c Ts are applicable to
  214. * the metafunction \c F and if so nest inside (a layer deeper) the <em>metafunction call</em>.
  215. *
  216. * \tparam F The metafunction
  217. * \tparam Ts The parameters (arguments) to \c F
  218. */
  219. template<template<class...> class F, class... Ts>
  220. using defer = if_<
  221. details::is_applicable_<F, Ts...>,
  222. details::defer_<F, Ts...>,
  223. nil_ //!< Safe, nil_ is dereferencable
  224. >;
  225. /*!
  226. * \brief
  227. * Postpone the instantiation of a metafunction \c F with parameters \c Is of type \c T.
  228. *
  229. * This metafunction first checks if the given arguments \c Is of type \c T are applicable to
  230. * the metafunction \c F and if so nest inside (a layer deeper) the <em>metafunction call</em>.
  231. *
  232. * \tparam T The type of parameters
  233. * \tparam F The metafunction
  234. * \tparam Is The parameters (arguments) to \c F
  235. */
  236. template <typename T, template<T...> class F, T... Is>
  237. using defer_i = if_ <
  238. details::is_applicable_i_<T, F, Is...>,
  239. details::defer_i_<T, F, Is...>,
  240. nil_ //!< Safe, nil_ is dereferencable
  241. >;
  242. //! @}
  243. //! \name quote
  244. //! @{
  245. /*!
  246. * \brief
  247. * Wraps an n-ary Metafunction \c F to a Metafunction Class using meta::defer<>
  248. *
  249. * quote is a higher-order primitive that wraps an n-ary Metafunction
  250. * to create a corresponding Metafunction Class (Invocable) using defer<> to
  251. * postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.\n
  252. * Again this way we can pass Metafunctions as types to other metafunctions and let
  253. * them \c invoke the inner templated apply
  254. *
  255. * \tparam F The metafunction to wrap
  256. */
  257. template <template <typename...> class F>
  258. struct quote {
  259. template <typename... Args>
  260. using apply = eval<
  261. defer<F, Args...> //!< defer here to avoid DR1430
  262. >;
  263. };
  264. /*!
  265. * \brief
  266. * Wraps an n-ary Metafunction \c F taking literal constants of type \c T
  267. * to a Metafunction Class using meta::defer<>
  268. *
  269. * quote is a higher-order primitive that wraps an n-ary Metafunction
  270. * to create a corresponding Metafunction Class (Invocable) using defer<> to
  271. * postpone the evaluation of Metafunction. This is a safe version of \c wrap<>.\n
  272. * Again this way we can pass Metafunctions as types to other metafunctions and let
  273. * them \c invoke the inner templated apply
  274. *
  275. * \tparam T Type of integral constants
  276. * \tparam F The metafunction to wrap
  277. */
  278. template <typename T, template <T...> class F>
  279. struct quote_i {
  280. // requires meta::Integral
  281. template <typename... Ts>
  282. using apply = eval<
  283. defer_i<T, F, Ts::type::value...> //!< defer here to avoid DR1430
  284. >;
  285. };
  286. //! @}
  287. //! \name compose
  288. //! @{
  289. namespace details {
  290. template <template <typename...> class... Fns> struct compose_f_ {};
  291. // recursive call to all invokes
  292. template <template <typename...> class Fn0,
  293. template <typename...> class... Fns>
  294. struct compose_f_<Fn0, Fns...> {
  295. template <typename... Args>
  296. using apply = invoke<
  297. quote<Fn0>,
  298. invoke<compose_f_<Fns...>, Args...>
  299. >;
  300. };
  301. // Termination specialization, finally pass the arguments
  302. template <template <typename...> class Fn0>
  303. struct compose_f_<Fn0> {
  304. template <typename ...Args>
  305. using apply = invoke<quote<Fn0>, Args...>;
  306. };
  307. template<typename ...Fns> struct compose_ {};
  308. // recursive call to all invokes
  309. template<typename Fn0, typename ...Fns>
  310. struct compose_<Fn0, Fns...> {
  311. template <typename ...Args>
  312. using apply = invoke<
  313. Fn0,
  314. invoke<compose_<Fns...>, Args...>
  315. >;
  316. };
  317. // Termination specialization, finally pass the arguments
  318. template<typename Fn0>
  319. struct compose_<Fn0> {
  320. template <typename... Args>
  321. using apply = invoke<Fn0, Args...>;
  322. };
  323. }
  324. /*!
  325. * \brief
  326. * Create an invocable from other invocables(quoted metafunctions) by composition.
  327. * \note
  328. * This implies from N invocables in \p Fns the first N-1 has to be unary.
  329. * Thats because of the "return" type of metafunction. They can only return one
  330. * type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
  331. *
  332. * \code
  333. * static_assert( std::is_same<
  334. * invoke<compose<quote<F1>, quote<F2>, quote<F3>>, int>, F1<F2<F3<int>>>
  335. * >, "");
  336. * \endcode
  337. */
  338. template <typename... Fns>
  339. using compose = details::compose_<Fns...>;
  340. /*!
  341. * \brief
  342. * Create an invocable from other metafunctions by composition.
  343. * \note
  344. * This implies from N invocables in \p Fns the first N-1 has to be unary.
  345. * Thats because of the "return" type of metafunction. They can only return one
  346. * type. So for n-ary invocables in the N-1 places the typelist<> is the solution.
  347. *
  348. * \code
  349. * static_assert( std::is_same<
  350. * invoke<compose_f<F1, F2, F3>, int>, F1 <F2 <F3 <int>>>
  351. * >, "");
  352. * \endcode
  353. */
  354. template <template <typename...> class... Fns>
  355. using compose_f = details::compose_f_<Fns...>;
  356. //! @}
  357. /*!
  358. * \brief
  359. * Applies the invocable \p Fn by binding the arguments \p Ts to the front of \p Fn.
  360. */
  361. template<typename Fn, typename... Ts>
  362. struct bind_front {
  363. template<typename... Us>
  364. using apply = invoke<Fn, Ts..., Us...>;
  365. };
  366. /*!
  367. * \brief
  368. * Applies the Invocable \p Fn by binding the arguments \p Ts to the back of \p Fn.
  369. */
  370. template<typename Fn, typename... Ts>
  371. struct bind_back {
  372. template<typename... Us>
  373. using apply = invoke<Fn, Us..., Ts...>;
  374. };
  375. /*
  376. * ========== meta:: predicates ============
  377. */
  378. template <typename T1>
  379. struct same_as {
  380. template <typename T2>
  381. struct apply : same_<T1, T2> { };
  382. };
  383. template <typename T1>
  384. struct not_same_as {
  385. template <typename T2>
  386. struct apply : not_same_<T1, T2> { };
  387. };
  388. }}
  389. //! @}
  390. #endif /* __utl_meta_invoke_h__ */