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 
63 namespace boost { namespace hof { namespace detail {
64 
65 template<class F, class NoExcept>
66 struct lift_noexcept : F
67 {
68     BOOST_HOF_INHERIT_CONSTRUCTOR(lift_noexcept, F);
69 
70     template<class... Ts>
operator ()boost::hof::detail::lift_noexcept71     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 
77 template<class F, class NoExcept>
make_lift_noexcept(F f,NoExcept)78 constexpr 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, ...) \
103 struct 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