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.
 
 
 
 

229 lignes
8.7 KiB

  1. /*!
  2. * \file detection.h
  3. * \brief Detection idiom based on WG21's N4502 from Walter E. Brown
  4. */
  5. #ifndef __utl_meta_detection_h__
  6. #define __utl_meta_detection_h__
  7. #include <utl/core/impl.h>
  8. #include <utl/meta/basic.h>
  9. #include <type_traits>
  10. /*!
  11. * \ingroup meta
  12. * \defgroup detection Detection
  13. * Detection idiom support header.
  14. */
  15. //! @{
  16. namespace utl {
  17. namespace meta {
  18. /*!
  19. * \name void_t implementation
  20. */
  21. //! @{
  22. #if defined(UTL_WORKAROUND_CWG_1558)
  23. template<typename... _Ts>
  24. struct void_ {
  25. using type = void;
  26. };
  27. //! void_t type alias
  28. template<typename... _Ts>
  29. using void_t = eval<void_<_Ts...>>;
  30. #else
  31. //! void_ meta-function that maps a sequence of any types to the type void
  32. template <typename...> using void_ = void;
  33. //! void_t meta-function that maps a sequence of any types to the type void
  34. template <typename...> using void_t = void;
  35. #endif
  36. //! @}
  37. /*!
  38. * \brief
  39. * Not a type to use in detected idiom.
  40. *
  41. * This type can not be constructed, destructed or copied.
  42. */
  43. struct nat_ {
  44. nat_() = delete;
  45. ~nat_() = delete;
  46. nat_(nat_ const&) = delete;
  47. void operator = (nat_ const&) = delete;
  48. };
  49. //! \name Detector for detection idiom
  50. //! @{
  51. namespace details {
  52. template <typename Default,
  53. typename AlwaysVoid,
  54. template<typename...> class Op, typename... Args>
  55. struct detector {
  56. using detected = false_;
  57. using type = Default;
  58. };
  59. template <typename Default,
  60. template<typename...> class Op, typename... Args>
  61. struct detector <Default, void_t<Op<Args...>>, Op, Args...> {
  62. using detected = true_;
  63. using type = Op<Args...>;
  64. };
  65. //! helper for detected_or_t
  66. template <typename Default,
  67. template<typename...> class Op, typename... Args>
  68. using detected_or = detector<Default, void, Op, Args...>;
  69. } // namespace details
  70. //! @}
  71. /*!
  72. * \name detection interface
  73. */
  74. //! @{
  75. /*!
  76. * Checks if Op<Args...> is a valid expression without evaluating it.
  77. *
  78. * \tparam Op a meta-callback function to pass Args...
  79. * \tparam Args... types to pass to Op for checking
  80. * \return status of the operation [bool_]
  81. * \arg true_ if Op<Args...> is valid expression
  82. * \arg false_ if Op<Args...> is not valid
  83. *
  84. * \code
  85. * // archetypal alias for a copy assignment operation
  86. * template< class T > using copy_assign_t = decltype( declval<T&>() = declval<T const &>() );
  87. *
  88. * template< class T > using is_copy_assignable = is_detected< copy_assign_t, T >;
  89. * \endcode
  90. */
  91. template <template<typename...> class Op, typename... Args>
  92. using is_detected = typename details::detector<nat_, void, Op, Args...>::detected;
  93. //! Detection predicate
  94. template< template<typename...> class Op, typename... Args>
  95. constexpr bool is_detected_v = is_detected<Op, Args...>::value;
  96. /*!
  97. * Detection tool that evaluates to Op<Args...> if it's valid and to nat_ if not
  98. *
  99. * \tparam Op metafunction detector
  100. * \tparam Args... The arguments to pass to \p Op and check if is well formed
  101. * \return The result type
  102. * \arg Op<Args...> if is well formed
  103. * \arg nat_ if Op<Args...> is ill formed
  104. *
  105. * \code
  106. * template <typename T> using try_type = typename T::type; // detector
  107. * template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
  108. * static_assert( std::is_same<nat_, detected_t<try_type, A<int>> >(), ""); // detection failed
  109. * static_assert( std::is_same<A<int>&, detected_t<try_ppT, A<int>> >(), ""); // detection succeed
  110. *
  111. * // if mFun<int, int> is well formed
  112. * static_assert(std::is_same< mFun<int, int>, detected_t<mFun, int, int> >(), "");
  113. * \endcode
  114. */
  115. template <template<typename...> class Op, typename... Args>
  116. using detected_t = eval <
  117. details::detector<nat_, void, Op, Args...>
  118. >;
  119. /*!
  120. * Detection tool that evaluates to Op<Args...> if it's valid and to \p Default if not
  121. *
  122. * \tparam Default The resulting type if detection fail
  123. * \tparam Op metafunction detector
  124. * \tparam Args... The arguments to pass to \p Op and check if is well formed
  125. * \return The result type
  126. * \arg Op<Args...> if is well formed
  127. * \arg Default if Op<Args...> is ill formed
  128. *
  129. * \code
  130. * template <typename T> using try_type = typename T::type; // detector
  131. * template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
  132. * static_assert( std::is_same<Foo, detected_or_t<Foo, try_type, A<int>> >(), ""); // detection failed
  133. * static_assert( std::is_same<A<int>&, detected_or_t<Foo, try_ppT, A<int>> >(), ""); // detection succeed
  134. *
  135. * // if mFun<int, int> is well formed
  136. * static_assert(std::is_same< mFun<int, int>, detected_or_t<void, mFun, int, int> >(), "");
  137. * \endcode
  138. */
  139. template <typename Default,
  140. template<typename...> class Op, typename... Args>
  141. using detected_or_t = eval <
  142. details::detected_or<Default, Op, Args...>
  143. >;
  144. /*!
  145. * Detection tool that evaluates to true_ if evaluation of Op<Args...>
  146. * is \p Expected and to false_ if not
  147. *
  148. * \tparam Expected The expected resulting type if detection succeed
  149. * \tparam Op metafunction detector
  150. * \tparam Args... The arguments to pass to \p Op and check if is well formed
  151. * \return The result type
  152. * \arg true_ if Op<Args...> is well formed and evaluate to Expected
  153. * \arg false_ Any other case
  154. *
  155. * \code
  156. * template <typename T> using try_type = typename T::type; // detector
  157. * template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
  158. * static_assert( std::is_same<false_, is_detected_exact<int, try_type, A<int>> >(), ""); // detection failed
  159. * static_assert( std::is_same<true_, is_detected_exact<A<int>&, try_ppT, A<int>> >(), ""); // detection succeed
  160. *
  161. * // if mFun<int, int> is well formed
  162. * static_assert(std::is_same< true_, is_detected_exact<mFun<int, int>, mFun, int, int> >(), "");
  163. * \endcode
  164. */
  165. template <typename Expected,
  166. template<typename...> class Op, typename... Args >
  167. using is_detected_exact = eval <
  168. same<Expected, detected_t<Op, Args...>>
  169. >;
  170. //! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
  171. template <typename Expected,
  172. template<typename...> class Op, typename... Args >
  173. constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value;
  174. /*!
  175. * Detection tool that evaluates to true_ if evaluation of Op<Args...> is convertible
  176. * to \p To and to false_ if not
  177. *
  178. * \tparam To The to convert to if detection succeed
  179. * \tparam Op metafunction detector
  180. * \tparam Args... The arguments to pass to \p Op and check if is well formed
  181. * \return The result type
  182. * \arg true_ if Op<Args...> is well formed and convertible to To
  183. * \arg false_ Any other case
  184. *
  185. * \code
  186. * template <typename T> using try_type = typename T::type; // detector
  187. * template <typename T> using try_ppT = decltype (++(std::declval<T>())); // detector
  188. * static_assert( std::is_same<false_, is_detected_convertible<Foo, try_type, A<int>> >(), ""); // detection failed
  189. * static_assert( std::is_same<true_, is_detected_convertible<A<int>&&, try_ppT, A<int>> >(), "");// detection succeed
  190. *
  191. * // if mFun<int, int> is well formed but not convertible to Foo
  192. * static_assert(std::is_same< false_, is_detected_convertible<Foo, mFun, int, int> >(), "");
  193. * \endcode
  194. */
  195. template <typename To,
  196. template<typename...> class Op, typename... Args >
  197. using is_detected_convertible = eval <
  198. std::is_convertible< detected_t<Op, Args...>, To >
  199. >;
  200. //! evaluates to true if evaluation of Op<Args...> is convertible to \p To
  201. //! and to false if not
  202. template <typename To,
  203. template<typename...> class Op, typename... Args >
  204. constexpr bool is_detected_convertible_v =
  205. is_detected_convertible<To, Op, Args...>::value;
  206. //! @}
  207. }}
  208. //!@}
  209. #endif /* __utl_meta_detection_h__ */