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.

bind.hpp 3.1KB

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