lift.hpp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /*=============================================================================
  2. Copyright (c) 2015 Paul Fultz II
  3. lift.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_FUNCTION_LIFT_H
  8. #define BOOST_HOF_GUARD_FUNCTION_LIFT_H
  9. /// BOOST_HOF_LIFT
  10. /// ========
  11. ///
  12. /// Description
  13. /// -----------
  14. ///
  15. /// The macros `BOOST_HOF_LIFT` and `BOOST_HOF_LIFT_CLASS` provide a lift operator that
  16. /// will wrap a template function in a function object so it can be passed to
  17. /// higher-order functions. The `BOOST_HOF_LIFT` macro will wrap the function using
  18. /// a generic lambda. As such, it will not preserve `constexpr`. The
  19. /// `BOOST_HOF_LIFT_CLASS` can be used to declare a class that will wrap function.
  20. /// This will preserve `constexpr` and it can be used on older compilers that
  21. /// don't support generic lambdas yet.
  22. ///
  23. /// Limitation
  24. /// ----------
  25. ///
  26. /// In C++14, `BOOST_HOF_LIFT` doesn't support `constexpr` due to using a generic
  27. /// lambda. Instead, `BOOST_HOF_LIFT_CLASS` can be used. In C++17, there is no such
  28. /// limitation.
  29. ///
  30. /// Synopsis
  31. /// --------
  32. ///
  33. /// // Wrap the function in a generic lambda
  34. /// #define BOOST_HOF_LIFT(...)
  35. ///
  36. /// // Declare a class named `name` that will forward to the function
  37. /// #define BOOST_HOF_LIFT_CLASS(name, ...)
  38. ///
  39. /// Example
  40. /// -------
  41. ///
  42. /// #include <boost/hof.hpp>
  43. /// #include <cassert>
  44. /// #include <algorithm>
  45. ///
  46. /// // Declare the class `max_f`
  47. /// BOOST_HOF_LIFT_CLASS(max_f, std::max);
  48. ///
  49. /// int main() {
  50. /// auto my_max = BOOST_HOF_LIFT(std::max);
  51. /// assert(my_max(3, 4) == std::max(3, 4));
  52. /// assert(max_f()(3, 4) == std::max(3, 4));
  53. /// }
  54. ///
  55. #include <boost/hof/detail/delegate.hpp>
  56. #include <boost/hof/returns.hpp>
  57. #include <boost/hof/lambda.hpp>
  58. #include <boost/hof/detail/forward.hpp>
  59. namespace boost { namespace hof { namespace detail {
  60. template<class F, class NoExcept>
  61. struct lift_noexcept : F
  62. {
  63. BOOST_HOF_INHERIT_CONSTRUCTOR(lift_noexcept, F);
  64. template<class... Ts>
  65. constexpr auto operator()(Ts&&... xs) const
  66. noexcept(decltype(std::declval<NoExcept>()(BOOST_HOF_FORWARD(Ts)(xs)...)){})
  67. -> decltype(std::declval<F>()(BOOST_HOF_FORWARD(Ts)(xs)...))
  68. { return F(*this)(BOOST_HOF_FORWARD(Ts)(xs)...);}
  69. };
  70. template<class F, class NoExcept>
  71. constexpr lift_noexcept<F, NoExcept> make_lift_noexcept(F f, NoExcept)
  72. {
  73. return {f};
  74. }
  75. }
  76. }} // namespace boost::hof
  77. #define BOOST_HOF_LIFT_IS_NOEXCEPT(...) std::integral_constant<bool, noexcept(decltype(__VA_ARGS__)(__VA_ARGS__))>{}
  78. #if defined (_MSC_VER)
  79. #define BOOST_HOF_LIFT(...) (BOOST_HOF_STATIC_LAMBDA { BOOST_HOF_LIFT_CLASS(fit_local_lift_t, __VA_ARGS__); return fit_local_lift_t(); }())
  80. #elif defined (__clang__)
  81. #define BOOST_HOF_LIFT(...) (boost::hof::detail::make_lift_noexcept( \
  82. BOOST_HOF_STATIC_LAMBDA(auto&&... xs) \
  83. -> decltype((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...)) \
  84. { return (__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...); }, \
  85. BOOST_HOF_STATIC_LAMBDA(auto&&... xs) { return BOOST_HOF_LIFT_IS_NOEXCEPT((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...)); } \
  86. ))
  87. #else
  88. #define BOOST_HOF_LIFT(...) (BOOST_HOF_STATIC_LAMBDA(auto&&... xs) BOOST_HOF_RETURNS((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...)))
  89. #endif
  90. #define BOOST_HOF_LIFT_CLASS(name, ...) \
  91. struct name \
  92. { \
  93. template<class... Ts> \
  94. constexpr auto operator()(Ts&&... xs) const \
  95. BOOST_HOF_RETURNS((__VA_ARGS__)(BOOST_HOF_FORWARD(Ts)(xs)...)) \
  96. }
  97. #endif