bind.hpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  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_BIND_HPP
  14. #define RANGES_V3_FUNCTIONAL_BIND_HPP
  15. #include <functional>
  16. #include <type_traits>
  17. #include <meta/meta.hpp>
  18. #include <concepts/concepts.hpp>
  19. #include <range/v3/range_fwd.hpp>
  20. #include <range/v3/utility/static_const.hpp>
  21. #include <range/v3/detail/prologue.hpp>
  22. namespace ranges
  23. {
  24. /// \addtogroup group-functional
  25. /// @{
  26. template<typename T,
  27. typename U = meta::if_<
  28. std::is_lvalue_reference<T>,
  29. std::reference_wrapper<meta::_t<std::remove_reference<T>>>, T &&>>
  30. U bind_forward(meta::_t<std::remove_reference<T>> & t) noexcept
  31. {
  32. return static_cast<U>(t);
  33. }
  34. template<typename T>
  35. T && bind_forward(meta::_t<std::remove_reference<T>> && t) noexcept
  36. {
  37. // This is to catch way sketchy stuff like: forward<int const &>(42)
  38. static_assert(!std::is_lvalue_reference<T>::value, "You didn't just do that!");
  39. return static_cast<T &&>(t);
  40. }
  41. template<typename T>
  42. struct bind_element
  43. : meta::if_c<RANGES_IS_SAME(detail::decay_t<T>, T), meta::id<T>,
  44. bind_element<detail::decay_t<T>>>
  45. {};
  46. template<typename T>
  47. struct bind_element<std::reference_wrapper<T>>
  48. {
  49. using type = T &;
  50. };
  51. template<typename T>
  52. struct bind_element<reference_wrapper<T>>
  53. {
  54. using type = typename reference_wrapper<T>::reference;
  55. };
  56. template<typename T>
  57. using bind_element_t = meta::_t<bind_element<T>>;
  58. template<typename Bind>
  59. struct protector
  60. {
  61. private:
  62. Bind bind_;
  63. public:
  64. protector() = default;
  65. protector(Bind b)
  66. : bind_(std::move(b))
  67. {}
  68. // clang-format off
  69. template<typename...Ts>
  70. auto CPP_auto_fun(operator())(Ts &&...ts)
  71. (
  72. return bind_(static_cast<Ts &&>(ts)...)
  73. )
  74. /// \overload
  75. template<typename...Ts>
  76. auto CPP_auto_fun(operator())(Ts &&...ts) (const)
  77. (
  78. return bind_(static_cast<Ts &&>(ts)...)
  79. )
  80. // clang-format on
  81. };
  82. struct protect_fn
  83. {
  84. template(typename F)(
  85. requires std::is_bind_expression<uncvref_t<F>>::value) //
  86. protector<uncvref_t<F>> operator()(F && f) const
  87. {
  88. return {static_cast<F &&>(f)};
  89. }
  90. /// \overload
  91. template(typename F)(
  92. requires (!std::is_bind_expression<uncvref_t<F>>::value)) //
  93. F operator()(F && f) const
  94. {
  95. return static_cast<F &&>(f);
  96. }
  97. };
  98. /// Protect a callable so that it can be safely used in a bind expression without
  99. /// accidentally becoming a "nested" bind.
  100. /// \ingroup group-functional
  101. /// \sa `protect_fn`
  102. RANGES_INLINE_VARIABLE(protect_fn, protect)
  103. /// @}
  104. } // namespace ranges
  105. #include <range/v3/detail/epilogue.hpp>
  106. #endif