alias.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*=============================================================================
  2. Copyright (c) 2015 Paul Fultz II
  3. alias.h
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. ==============================================================================*/
  7. #ifndef BOOST_HOF_GUARD_ALIAS_H
  8. #define BOOST_HOF_GUARD_ALIAS_H
  9. #include <boost/hof/returns.hpp>
  10. #include <boost/hof/detail/delegate.hpp>
  11. #include <boost/hof/detail/move.hpp>
  12. #include <boost/hof/detail/holder.hpp>
  13. #include <boost/hof/config.hpp>
  14. /// alias
  15. /// =====
  16. ///
  17. /// Description
  18. /// -----------
  19. ///
  20. /// The `alias` class wraps a type with a new type that can be tagged by the
  21. /// user. This allows defining extra attributes about the type outside of the
  22. /// type itself. There are three different ways the value can be stored: as a
  23. /// member variable, by inheritance, or as a static member variable. The value
  24. /// can be retrieved uniformily using the `alias_value` function.
  25. ///
  26. /// Synopsis
  27. /// --------
  28. ///
  29. /// // Alias the type using a member variable
  30. /// template<class T, class Tag=void>
  31. /// class alias;
  32. ///
  33. /// // Alias the type by inheriting
  34. /// template<class T, class Tag=void>
  35. /// class alias_inherit;
  36. ///
  37. /// // Alias the type using a static variable
  38. /// template<class T, class Tag=void>
  39. /// class alias_static;
  40. ///
  41. /// // Retrieve tag from alias
  42. /// template<class Alias>
  43. /// class alias_tag;
  44. ///
  45. /// // Check if type has a certian tag
  46. /// template<class T, class Tag>
  47. /// class has_tag;
  48. ///
  49. /// // Retrieve value from alias
  50. /// template<class Alias>
  51. /// constexpr auto alias_value(Alias&&);
  52. ///
  53. #ifdef _MSC_VER
  54. #pragma warning(push)
  55. #pragma warning(disable: 4579)
  56. #endif
  57. namespace boost { namespace hof {
  58. template<class T>
  59. struct alias_tag;
  60. template<class T, class Tag, class=void>
  61. struct has_tag
  62. : std::false_type
  63. {};
  64. template<class T, class Tag>
  65. struct has_tag<T, Tag, typename detail::holder<
  66. typename alias_tag<T>::type
  67. >::type>
  68. : std::is_same<typename alias_tag<T>::type, Tag>
  69. {};
  70. namespace detail {
  71. template<class T>
  72. constexpr T& lvalue(T& x) noexcept
  73. {
  74. return x;
  75. }
  76. template<class T>
  77. constexpr const T& lvalue(const T& x) noexcept
  78. {
  79. return x;
  80. }
  81. }
  82. #define BOOST_HOF_UNARY_PERFECT_FOREACH(m) \
  83. m(const&, boost::hof::detail::lvalue) \
  84. m(&, boost::hof::detail::lvalue) \
  85. m(&&, boost::hof::move) \
  86. template<class T, class Tag=void>
  87. struct alias
  88. {
  89. T value;
  90. BOOST_HOF_DELEGATE_CONSTRUCTOR(alias, T, value)
  91. };
  92. #define BOOST_HOF_DETAIL_ALIAS_GET_VALUE(ref, move) \
  93. template<class Tag, class T, class... Ts> \
  94. constexpr auto alias_value(alias<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS(move(a.value))
  95. BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_GET_VALUE)
  96. template<class T, class Tag>
  97. struct alias_tag<alias<T, Tag>>
  98. { typedef Tag type; };
  99. template<class T, class Tag=void>
  100. struct alias_inherit
  101. #if (defined(__GNUC__) && !defined (__clang__))
  102. : std::conditional<(std::is_class<T>::value), T, alias<T>>::type
  103. #else
  104. : T
  105. #endif
  106. {
  107. BOOST_HOF_INHERIT_CONSTRUCTOR(alias_inherit, T)
  108. };
  109. #define BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE(ref, move) \
  110. template<class Tag, class T, class... Ts, class=typename std::enable_if<(BOOST_HOF_IS_CLASS(T))>::type> \
  111. constexpr T ref alias_value(alias_inherit<T, Tag> ref a, Ts&&...) BOOST_HOF_RETURNS_DEDUCE_NOEXCEPT(move(a)) \
  112. { \
  113. return move(a); \
  114. }
  115. BOOST_HOF_UNARY_PERFECT_FOREACH(BOOST_HOF_DETAIL_ALIAS_INHERIT_GET_VALUE)
  116. template<class T, class Tag>
  117. struct alias_tag<alias_inherit<T, Tag>>
  118. { typedef Tag type; };
  119. namespace detail {
  120. template<class T, class Tag>
  121. struct alias_static_storage
  122. {
  123. #ifdef _MSC_VER
  124. // Since we disable the error for 4579 on MSVC, which leaves the static
  125. // member unitialized at runtime, it is, therefore, only safe to use this
  126. // class on types that are empty with constructors that have no possible
  127. // side effects.
  128. static_assert(BOOST_HOF_IS_EMPTY(T) &&
  129. BOOST_HOF_IS_LITERAL(T) &&
  130. BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T), "In-class initialization is not yet implemented on MSVC");
  131. #endif
  132. static constexpr T value = T();
  133. };
  134. template<class T, class Tag>
  135. constexpr T alias_static_storage<T, Tag>::value;
  136. }
  137. template<class T, class Tag=void>
  138. struct alias_static
  139. {
  140. template<class... Ts, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, Ts...)>
  141. constexpr alias_static(Ts&&...) noexcept
  142. {}
  143. };
  144. template<class Tag, class T, class... Ts>
  145. constexpr const T& alias_value(const alias_static<T, Tag>&, Ts&&...) noexcept
  146. {
  147. return detail::alias_static_storage<T, Tag>::value;
  148. }
  149. template<class T, class Tag>
  150. struct alias_tag<alias_static<T, Tag>>
  151. { typedef Tag type; };
  152. namespace detail {
  153. template<class T, class Tag>
  154. struct alias_try_inherit
  155. : std::conditional<(BOOST_HOF_IS_CLASS(T) && !BOOST_HOF_IS_FINAL(T) && !BOOST_HOF_IS_POLYMORPHIC(T)),
  156. alias_inherit<T, Tag>,
  157. alias<T, Tag>
  158. >
  159. {};
  160. #if BOOST_HOF_HAS_EBO
  161. template<class T, class Tag>
  162. struct alias_empty
  163. : std::conditional<(BOOST_HOF_IS_EMPTY(T)),
  164. typename alias_try_inherit<T, Tag>::type,
  165. alias<T, Tag>
  166. >
  167. {};
  168. #else
  169. template<class T, class Tag>
  170. struct alias_empty
  171. : std::conditional<
  172. BOOST_HOF_IS_EMPTY(T) &&
  173. BOOST_HOF_IS_LITERAL(T) &&
  174. BOOST_HOF_IS_DEFAULT_CONSTRUCTIBLE(T),
  175. alias_static<T, Tag>,
  176. alias<T, Tag>
  177. >
  178. {};
  179. #endif
  180. }
  181. }} // namespace boost::hof
  182. #ifdef _MSC_VER
  183. #pragma warning(pop)
  184. #endif
  185. #endif