• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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