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.
 
 
 
 

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