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.
 
 
 
 

172 lines
5.5 KiB

  1. /*!
  2. * \file detection.h
  3. * \brief Detection idiom based on WG21's N4502[1] from Walter E. Brown
  4. *
  5. * [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/logical.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
  56. */
  57. struct nat_ {
  58. nat_() = delete;
  59. ~nat_() = delete;
  60. nat_(nat_ const&) = delete;
  61. void operator = (nat_ const&) = delete;
  62. };
  63. //! Detector for detection idiom
  64. //! @{
  65. namespace detail {
  66. template <typename Default,
  67. typename AlwaysVoid,
  68. template<typename...> class Op, typename... Args>
  69. struct detector {
  70. using detected = false_;
  71. using type = Default;
  72. };
  73. template <typename Default,
  74. template<typename...> class Op, typename... Args>
  75. struct detector <Default, void_t<Op<Args...>>, Op, Args...> {
  76. using detected = true_;
  77. using type = Op<Args...>;
  78. };
  79. //! helper for detected_or_t
  80. template <typename Default,
  81. template<typename...> class Op, typename... Args>
  82. using detected_or = detector<Default, void, Op, Args...>;
  83. } // namespace detail
  84. //! @}
  85. /*!
  86. * detection interface
  87. */
  88. //! @{
  89. /*!
  90. * Checks if Op<Args...> is a valid expression without evaluating it.
  91. *
  92. * \param Op a meta-callback function to pass Args...
  93. * \param Args... types to pass to Op for checking
  94. * \return status of the operation [bool_]
  95. * \arg true_ if Op<Args...> is valid expression
  96. * \arg false_ if Op<Args...> is not valid
  97. *
  98. * \example
  99. * \code
  100. * // archetypal alias for a copy assignment operation
  101. * template< class T >
  102. * using copy_assign_t = decltype( declval<T&>() = declval<T const &>() );
  103. *
  104. * template< class T >
  105. * using is_copy_assignable = is_detected< T, copy_assign_t >;
  106. * \endcode
  107. */
  108. template <template<typename...> class Op, typename... Args>
  109. using is_detected = typename detail::detector<nat_, void, Op, Args...>::detected;
  110. //! Detection predicate
  111. template< template<typename...> class Op, typename... Args>
  112. constexpr bool is_detected_v = is_detected<Op, Args...>::value;
  113. //! @}
  114. /*!
  115. * Detection idiom toolkit
  116. */
  117. //! @{
  118. //! evaluates to evaluation of Op<Args...> if it's valid and to nat_ if not
  119. template <template<typename...> class Op, typename... Args>
  120. using detected_t = eval <
  121. detail::detector<nat_, void, Op, Args...>
  122. >;
  123. //! evaluates to evaluation of Op<Args...> if it's valid and to \p Default if not
  124. template <typename Default,
  125. template<typename...> class Op, typename... Args>
  126. using detected_or_t = eval <
  127. detail::detected_or<Default, Op, Args...>
  128. >;
  129. //! evaluates to true_ if evaluation of Op<Args...> is \p Expected and to false_ if not
  130. template <typename Expected,
  131. template<typename...> class Op, typename... Args >
  132. using is_detected_exact = same_<Expected, detected_t<Op, Args...> >;
  133. //! evaluates to true if evaluation of Op<Args...> is \p Expected and to false if not
  134. template <typename Expected,
  135. template<typename...> class Op, typename... Args >
  136. constexpr bool is_detected_exact_v = is_detected_exact< Expected, Op, Args...>::value;
  137. //! evaluates to true_ if evaluation of Op<Args...> is convertible to \p To
  138. //! and to false_ if not
  139. template <typename To,
  140. template<typename...> class Op, typename... Args >
  141. using is_detected_convertible = std::is_convertible< detected_t<Op, Args...>, To >;
  142. //! evaluates to true if evaluation of Op<Args...> is convertible to \p To
  143. //! and to false if not
  144. template <typename To,
  145. template<typename...> class Op, typename... Args >
  146. constexpr bool is_detected_convertible_v =
  147. is_detected_convertible<To, Op, Args...>::value;
  148. //! @}
  149. }}
  150. //!@}
  151. #endif /* __utl_meta_detection_h__ */