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.
 
 
 
 

245 lignes
9.4 KiB

  1. /*!
  2. * \file detection.h
  3. * \brief Detection idiom based on WG21's N4502 [\ref n4502 1] from Walter E. Brown
  4. *
  5. * \anchor n4502 [1]: www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/n4502.pdf
  6. *
  7. * Copyright (C) 2018-2019 Christos Choutouridis
  8. *
  9. * This program is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU Lesser General Public License as
  11. * published by the Free Software Foundation, either version 3
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU Lesser General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Lesser General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. */
  22. #ifndef __utl_meta_detection_h__
  23. #define __utl_meta_detection_h__
  24. #include <utl/core/impl.h>
  25. #include <utl/meta/operations.h>
  26. #include <type_traits>
  27. /*!
  28. * \ingroup meta
  29. * \defgroup detection
  30. * Detection idiom support header.
  31. */
  32. //! @{
  33. namespace utl {
  34. namespace meta {
  35. /*!
  36. * void_t meta-function that maps a sequence of any types to the type void
  37. */
  38. //! @{
  39. #if defined(UTL_WORKAROUND_CWG_1558)
  40. template<typename... _Ts>
  41. struct void_ {
  42. using type = void;
  43. };
  44. //! void_t type alias
  45. template<typename... _Ts>
  46. using void_t = eval<void_<_Ts...>>;
  47. #else
  48. //! void_ type alias
  49. template <typename...> using void_ = void;
  50. //! void_t type alias
  51. template <typename...> using void_t = void;
  52. #endif
  53. //! @}
  54. /*!
  55. * Not a type to use in detected idiom. This type can
  56. * not be constructed, destructed or copied
  57. */
  58. struct nat_ {
  59. nat_() = delete;
  60. ~nat_() = delete;
  61. nat_(nat_ const&) = delete;
  62. void operator = (nat_ const&) = delete;
  63. };
  64. //! Detector for detection idiom
  65. //! @{
  66. namespace detail {
  67. template <typename Default,
  68. typename AlwaysVoid,
  69. template<typename...> class Op, typename... Args>
  70. struct detector {
  71. using detected = false_;
  72. using type = Default;
  73. };
  74. template <typename Default,
  75. template<typename...> class Op, typename... Args>
  76. struct detector <Default, void_t<Op<Args...>>, Op, Args...> {
  77. using detected = true_;
  78. using type = Op<Args...>;
  79. };
  80. //! helper for detected_or_t
  81. template <typename Default,
  82. template<typename...> class Op, typename... Args>
  83. using detected_or = detector<Default, void, Op, Args...>;
  84. } // namespace detail
  85. //! @}
  86. /*!
  87. * detection interface
  88. */
  89. //! @{
  90. /*!
  91. * Checks if Op<Args...> is a valid expression without evaluating it.
  92. *
  93. * \param Op a meta-callback function to pass Args...
  94. * \param Args... types to pass to Op for checking
  95. * \return status of the operation [bool_]
  96. * \arg true_ if Op<Args...> is valid expression
  97. * \arg false_ if Op<Args...> is not valid
  98. *
  99. * \example
  100. * \code
  101. * // archetypal alias for a copy assignment operation
  102. * template< class T > using copy_assign_t = decltype( declval<T&>() = declval<T const &>() );
  103. *
  104. * template< class T > using is_copy_assignable = is_detected< copy_assign_t, T >;
  105. * \endcode
  106. */
  107. template <template<typename...> class Op, typename... Args>
  108. using is_detected = typename detail::detector<nat_, void, Op, Args...>::detected;
  109. //! Detection predicate
  110. template< template<typename...> class Op, typename... Args>
  111. constexpr bool is_detected_v = is_detected<Op, Args...>::value;
  112. /*!
  113. * Detection tool that evaluates to Op<Args...> if it's valid and to nat_ if not
  114. *
  115. * \param Op metafunction detector
  116. * \param Args... The arguments to pass to \p Op and check if is well formed
  117. * \return The result type
  118. * \arg Op<Args...> if is well formed
  119. * \arg nat_ if Op<Args...> is ill formed
  120. * \example
  121. * \code
  122. * template <typename T> using try_type = typename T::type; // detector
  123. * template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
  124. * static_assert( std::is_same<nat_, detected_t<try_type, A<int>> >(), ""); // detection failed
  125. * static_assert( std::is_same<A<int>&, detected_t<try_ppT, A<int>> >(), ""); // detection succeed
  126. *
  127. * // if mFun<int, int> is well formed
  128. * static_assert(std::is_same< mFun<int, int>, detected_t<mFun, int, int> >(), "");
  129. * \endcode
  130. */
  131. template <template<typename...> class Op, typename... Args>
  132. using detected_t = eval <
  133. detail::detector<nat_, void, Op, Args...>
  134. >;
  135. /*!
  136. * Detection tool that evaluates to Op<Args...> if it's valid and to \p Default if not
  137. *
  138. * \param Default The resulting type if detection fail
  139. * \param Op metafunction detector
  140. * \param Args... The arguments to pass to \p Op and check if is well formed
  141. * \return The result type
  142. * \arg Op<Args...> if is well formed
  143. * \arg Default if Op<Args...> is ill formed
  144. * \example
  145. * \code
  146. * template <typename T> using try_type = typename T::type; // detector
  147. * template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
  148. * static_assert( std::is_same<Foo, detected_or_t<Foo, try_type, A<int>> >(), ""); // detection failed
  149. * static_assert( std::is_same<A<int>&, detected_or_t<Foo, try_ppT, A<int>> >(), ""); // detection succeed
  150. *
  151. * // if mFun<int, int> is well formed
  152. * static_assert(std::is_same< mFun<int, int>, detected_or_t<void, mFun, int, int> >(), "");
  153. * \endcode
  154. */
  155. template <typename Default,
  156. template<typename...> class Op, typename... Args>
  157. using detected_or_t = eval <
  158. detail::detected_or<Default, Op, Args...>
  159. >;
  160. /*!
  161. * Detection tool that evaluates to true_ if evaluation of Op<Args...>
  162. * is \p Expected and to false_ if not
  163. *
  164. * \param Expected The expected resulting type if detection succeed
  165. * \param Op metafunction detector
  166. * \param Args... The arguments to pass to \p Op and check if is well formed
  167. * \return The result type
  168. * \arg true_ if Op<Args...> is well formed and evaluate to Expected
  169. * \arg false_ Any other case
  170. * \example
  171. * \code
  172. * template <typename T> using try_type = typename T::type; // detector
  173. * template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
  174. * static_assert( std::is_same<false_, is_detected_exact<int, try_type, A<int>> >(), ""); // detection failed
  175. * static_assert( std::is_same<true_, is_detected_exact<A<int>&, try_ppT, A<int>> >(), ""); // detection succeed
  176. *
  177. * // if mFun<int, int> is well formed
  178. * static_assert(std::is_same< true_, is_detected_exact<mFun<int, int>, mFun, int, int> >(), "");
  179. * \endcode
  180. */
  181. template <typename Expected,
  182. template<typename...> class Op, typename... Args >
  183. using is_detected_exact = eval <
  184. same_<Expected, detected_t<Op, Args...>>
  185. >;
  186. //! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
  187. template <typename Expected,
  188. template<typename...> class Op, typename... Args >
  189. constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value;
  190. /*!
  191. * Detection tool that evaluates to true_ if evaluation of Op<Args...> is convertible
  192. * to \p To and to false_ if not
  193. *
  194. * \param To The to convert to if detection succeed
  195. * \param Op metafunction detector
  196. * \param Args... The arguments to pass to \p Op and check if is well formed
  197. * \return The result type
  198. * \arg true_ if Op<Args...> is well formed and convertible to To
  199. * \arg false_ Any other case
  200. * \example
  201. * \code
  202. * template <typename T> using try_type = typename T::type; // detector
  203. * template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
  204. * static_assert( std::is_same<false_, is_detected_convertible<Foo, try_type, A<int>> >(), ""); // detection failed
  205. * static_assert( std::is_same<true_, is_detected_convertible<A<int>&&, try_ppT, A<int>> >(), "");// detection succeed
  206. *
  207. * // if mFun<int, int> is well formed but not convertible to Foo
  208. * static_assert(std::is_same< false_, is_detected_convertible<Foo, mFun, int, int> >(), "");
  209. * \endcode
  210. */
  211. template <typename To,
  212. template<typename...> class Op, typename... Args >
  213. using is_detected_convertible = eval <
  214. std::is_convertible< detected_t<Op, Args...>, To >
  215. >;
  216. //! evaluates to true if evaluation of Op<Args...> is convertible to \p To
  217. //! and to false if not
  218. template <typename To,
  219. template<typename...> class Op, typename... Args >
  220. constexpr bool is_detected_convertible_v =
  221. is_detected_convertible<To, Op, Args...>::value;
  222. //! @}
  223. }}
  224. //!@}
  225. #endif /* __utl_meta_detection_h__ */