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