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.

193 lines
5.6KB

  1. /// \file
  2. // Range v3 library
  3. //
  4. // Copyright Eric Niebler 2013-present
  5. //
  6. // Use, modification and distribution is subject to the
  7. // Boost Software License, Version 1.0. (See accompanying
  8. // file LICENSE_1_0.txt or copy at
  9. // http://www.boost.org/LICENSE_1_0.txt)
  10. //
  11. // Project home: https://github.com/ericniebler/range-v3
  12. //
  13. #ifndef RANGES_V3_FUNCTIONAL_REFERENCE_WRAPPER_HPP
  14. #define RANGES_V3_FUNCTIONAL_REFERENCE_WRAPPER_HPP
  15. #include <type_traits>
  16. #include <utility>
  17. #include <meta/meta.hpp>
  18. #include <concepts/concepts.hpp>
  19. #include <range/v3/functional/invoke.hpp>
  20. #include <range/v3/functional/pipeable.hpp>
  21. #include <range/v3/utility/addressof.hpp>
  22. #include <range/v3/utility/static_const.hpp>
  23. namespace ranges
  24. {
  25. /// \addtogroup group-functional
  26. /// @{
  27. /// \cond
  28. namespace detail
  29. {
  30. template<typename T>
  31. struct reference_wrapper_
  32. {
  33. T * t_ = nullptr;
  34. constexpr reference_wrapper_() = default;
  35. constexpr reference_wrapper_(T & t) noexcept
  36. : t_(detail::addressof(t))
  37. {}
  38. constexpr reference_wrapper_(T &&) = delete;
  39. constexpr T & get() const noexcept
  40. {
  41. return *t_;
  42. }
  43. };
  44. template<typename T>
  45. struct reference_wrapper_<T &> : reference_wrapper_<T>
  46. {
  47. using reference_wrapper_<T>::reference_wrapper_;
  48. };
  49. template<typename T>
  50. struct reference_wrapper_<T &&>
  51. {
  52. T * t_ = nullptr;
  53. constexpr reference_wrapper_() = default;
  54. constexpr reference_wrapper_(T && t) noexcept
  55. : t_(detail::addressof(t))
  56. {}
  57. constexpr T && get() const noexcept
  58. {
  59. return static_cast<T &&>(*t_);
  60. }
  61. };
  62. } // namespace detail
  63. /// \endcond
  64. // Can be used to store rvalue references in addition to lvalue references.
  65. // Also, see: https://wg21.link/lwg2993
  66. template<typename T>
  67. struct reference_wrapper : private detail::reference_wrapper_<T>
  68. {
  69. private:
  70. using base_ = detail::reference_wrapper_<T>;
  71. using base_::t_;
  72. public:
  73. using type = meta::_t<std::remove_reference<T>>;
  74. using reference = meta::if_<std::is_reference<T>, T, T &>;
  75. constexpr reference_wrapper() = default;
  76. #if !defined(__clang__) || __clang_major__ > 3
  77. template<typename U>
  78. constexpr CPP_ctor(reference_wrapper)(U && u)( //
  79. noexcept(std::is_nothrow_constructible<base_, U>::value) //
  80. requires(!defer::same_as<uncvref_t<U>, reference_wrapper>) &&
  81. defer::constructible_from<base_, U>)
  82. : detail::reference_wrapper_<T>{static_cast<U &&>(u)}
  83. {}
  84. #else
  85. // BUGBUG clang-3.7 prefers a CPP_template here instead of a CPP_ctor
  86. CPP_template(typename U)( //
  87. requires(!defer::same_as<uncvref_t<U>, reference_wrapper>) &&
  88. defer::constructible_from<base_, U>) //
  89. constexpr reference_wrapper(U && u) noexcept(
  90. std::is_nothrow_constructible<base_, U>::value)
  91. : detail::reference_wrapper_<T>{static_cast<U &&>(u)}
  92. {}
  93. #endif
  94. constexpr reference get() const noexcept
  95. {
  96. return this->base_::get();
  97. }
  98. constexpr operator reference() const noexcept
  99. {
  100. return get();
  101. }
  102. CPP_template(typename...)( //
  103. requires(!std::is_rvalue_reference<T>::value)) //
  104. operator std::reference_wrapper<type>() const noexcept
  105. {
  106. return {get()};
  107. }
  108. // clang-format off
  109. template<typename ...Args>
  110. constexpr auto CPP_auto_fun(operator())(Args &&...args) (const)
  111. (
  112. return invoke(static_cast<reference>(*t_), static_cast<Args &&>(args)...)
  113. )
  114. // clang-format on
  115. };
  116. struct ref_fn : pipeable_base
  117. {
  118. template<typename T>
  119. auto operator()(T & t) const -> CPP_ret(reference_wrapper<T>)( //
  120. requires(!is_reference_wrapper_v<T>))
  121. {
  122. return {t};
  123. }
  124. /// \overload
  125. template<typename T>
  126. reference_wrapper<T> operator()(reference_wrapper<T> t) const
  127. {
  128. return t;
  129. }
  130. /// \overload
  131. template<typename T>
  132. reference_wrapper<T> operator()(std::reference_wrapper<T> t) const
  133. {
  134. return {t.get()};
  135. }
  136. };
  137. /// \ingroup group-functional
  138. /// \sa `ref_fn`
  139. RANGES_INLINE_VARIABLE(ref_fn, ref)
  140. template<typename T>
  141. using ref_t = decltype(ref(std::declval<T>()));
  142. struct unwrap_reference_fn
  143. {
  144. template<typename T>
  145. T && operator()(T && t) const noexcept
  146. {
  147. return static_cast<T &&>(t);
  148. }
  149. /// \overload
  150. template<typename T>
  151. typename reference_wrapper<T>::reference operator()(reference_wrapper<T> t) const
  152. noexcept
  153. {
  154. return t.get();
  155. }
  156. /// \overload
  157. template<typename T>
  158. T & operator()(std::reference_wrapper<T> t) const noexcept
  159. {
  160. return t.get();
  161. }
  162. /// \overload
  163. template<typename T>
  164. T & operator()(ref_view<T> t) const noexcept
  165. {
  166. return t.base();
  167. }
  168. };
  169. /// \ingroup group-functional
  170. /// \sa `unwrap_reference_fn`
  171. RANGES_INLINE_VARIABLE(unwrap_reference_fn, unwrap_reference)
  172. template<typename T>
  173. using unwrap_reference_t = decltype(unwrap_reference(std::declval<T>()));
  174. /// @}
  175. } // namespace ranges
  176. #endif