summaryrefslogtreecommitdiff
path: root/boost/hof/lift.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/hof/lift.hpp')
-rw-r--r--boost/hof/lift.hpp110
1 files changed, 110 insertions, 0 deletions
diff --git a/boost/hof/lift.hpp b/boost/hof/lift.hpp
new file mode 100644
index 0000000000..0fe6652db7
--- /dev/null
+++ b/boost/hof/lift.hpp
@@ -0,0 +1,110 @@
+/*=============================================================================
+ Copyright (c) 2015 Paul Fultz II
+ lift.h
+ Distributed under the Boost Software License, Version 1.0. (See accompanying
+ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+==============================================================================*/
+
+#ifndef BOOST_HOF_GUARD_FUNCTION_LIFT_H
+#define BOOST_HOF_GUARD_FUNCTION_LIFT_H
+
+/// BOOST_HOF_LIFT
+/// ========
+///
+/// Description
+/// -----------
+///
+/// The macros `BOOST_HOF_LIFT` and `BOOST_HOF_LIFT_CLASS` provide a lift operator that
+/// will wrap a template function in a function object so it can be passed to
+/// higher-order functions. The `BOOST_HOF_LIFT` macro will wrap the function using
+/// a generic lambda. As such, it will not preserve `constexpr`. The
+/// `BOOST_HOF_LIFT_CLASS` can be used to declare a class that will wrap function.
+/// This will preserve `constexpr` and it can be used on older compilers that
+/// don't support generic lambdas yet.
+///
+/// Limitation
+/// ----------
+///
+/// In C++14, `BOOST_HOF_LIFT` doesn't support `constexpr` due to using a generic
+/// lambda. Instead, `BOOST_HOF_LIFT_CLASS` can be used. In C++17, there is no such
+/// limitation.
+///
+/// Synopsis
+/// --------
+///
+/// // Wrap the function in a generic lambda
+/// #define BOOST_HOF_LIFT(...)
+///
+/// // Declare a class named `name` that will forward to the function
+/// #define BOOST_HOF_LIFT_CLASS(name, ...)
+///
+/// Example
+/// -------
+///
+/// #include <boost/hof.hpp>
+/// #include <cassert>
+/// #include <algorithm>
+///
+/// // Declare the class `max_f`
+/// BOOST_HOF_LIFT_CLASS(max_f, std::max);
+///
+/// int main() {
+/// auto my_max = BOOST_HOF_LIFT(std::max);
+/// assert(my_max(3, 4) == std::max(3, 4));
+/// assert(max_f()(3, 4) == std::max(3, 4));
+/// }
+///
+
+#include <boost/hof/detail/delegate.hpp>
+#include <boost/hof/returns.hpp>
+#include <boost/hof/lambda.hpp>
+#include <boost/hof/detail/forward.hpp>
+
+namespace boost { namespace hof { namespace detail {
+
+template<class F, class NoExcept>
+struct lift_noexcept : F
+{
+ BOOST_HOF_INHERIT_CONSTRUCTOR(lift_noexcept, F);
+
+ template<class... Ts>
+ constexpr auto operator()(Ts&&... xs) const
+ noexcept(decltype(std::declval<NoExcept>()(BOOST_HOF_FORWARD(Ts)(xs)...)){})
+ -> decltype(std::declval<F>()(BOOST_HOF_FORWARD(Ts)(xs)...))
+ { return F(*this)(BOOST_HOF_FORWARD(Ts)(xs)...);}
+};
+
+template<class F, class NoExcept>
+constexpr lift_noexcept<F, NoExcept> make_lift_noexcept(F f, NoExcept)
+{
+ return {f};
+}
+
+}
+
+}} // namespace boost::hof
+
+#define BOOST_HOF_LIFT_IS_NOEXCEPT(...) std::integral_constant<bool, noexcept(decltype(__VA_ARGS__)(__VA_ARGS__))>{}
+
+#if defined (_MSC_VER)
+#define BOOST_HOF_LIFT(...) (BOOST_HOF_STATIC_LAMBDA { BOOST_HOF_LIFT_CLASS(fit_local_lift_t, __VA_ARGS__); return fit_local_lift_t(); }())
+#elif defined (__clang__)
+#define BOOST_HOF_LIFT(...) (boost::hof::detail::make_lift_noexcept( \
+ BOOST_HOF_STATIC_LAMBDA(auto&&... xs) \
+ -> decltype((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...)) \
+ { return (__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...); }, \
+ BOOST_HOF_STATIC_LAMBDA(auto&&... xs) { return BOOST_HOF_LIFT_IS_NOEXCEPT((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...)); } \
+))
+#else
+#define BOOST_HOF_LIFT(...) (BOOST_HOF_STATIC_LAMBDA(auto&&... xs) BOOST_HOF_RETURNS((__VA_ARGS__)(BOOST_HOF_FORWARD(decltype(xs))(xs)...)))
+#endif
+
+#define BOOST_HOF_LIFT_CLASS(name, ...) \
+struct name \
+{ \
+ template<class... Ts> \
+ constexpr auto operator()(Ts&&... xs) const \
+ BOOST_HOF_RETURNS((__VA_ARGS__)(BOOST_HOF_FORWARD(Ts)(xs)...)) \
+}
+
+#endif