109 lines
3.4 KiB
C++
109 lines
3.4 KiB
C++
/*!
|
|
@file
|
|
Defines `boost::hana::compose`.
|
|
|
|
@copyright Louis Dionne 2013-2016
|
|
Distributed under the Boost Software License, Version 1.0.
|
|
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
|
|
*/
|
|
|
|
#ifndef BOOST_HANA_FUNCTIONAL_COMPOSE_HPP
|
|
#define BOOST_HANA_FUNCTIONAL_COMPOSE_HPP
|
|
|
|
#include <boost/hana/config.hpp>
|
|
#include <boost/hana/detail/create.hpp>
|
|
#include <boost/hana/detail/variadic/foldl1.hpp>
|
|
|
|
#include <utility>
|
|
|
|
|
|
BOOST_HANA_NAMESPACE_BEGIN
|
|
//! @ingroup group-functional
|
|
//! Return the composition of two functions or more.
|
|
//!
|
|
//! `compose` is defined inductively. When given more than two functions,
|
|
//! `compose(f, g, h...)` is equivalent to `compose(f, compose(g, h...))`.
|
|
//! When given two functions, `compose(f, g)` is a function such that
|
|
//! @code
|
|
//! compose(f, g)(x, y...) == f(g(x), y...)
|
|
//! @endcode
|
|
//!
|
|
//! If you need composition of the form `f(g(x, y...))`, use `demux` instead.
|
|
//!
|
|
//! @note
|
|
//! `compose` is an associative operation; `compose(f, compose(g, h))`
|
|
//! is equivalent to `compose(compose(f, g), h)`.
|
|
//!
|
|
//! @internal
|
|
//! ### Proof of associativity
|
|
//!
|
|
//! @code
|
|
//! compose(f, compose(g, h))(x, xs...) == f(compose(g, h)(x), xs...)
|
|
//! == f(g(h(x)), xs...)
|
|
//!
|
|
//! compose(compose(f, g), h)(x, xs...) == compose(f, g)(h(x), xs...)
|
|
//! == f(g(h(x)), xs...)
|
|
//! @endcode
|
|
//! @endinternal
|
|
//!
|
|
//! ### Example
|
|
//! @include example/functional/compose.cpp
|
|
#ifdef BOOST_HANA_DOXYGEN_INVOKED
|
|
constexpr auto compose = [](auto&& f1, auto&& f2, ..., auto&& fn) {
|
|
return [perfect-capture](auto&& x, auto&& ...xs) -> decltype(auto) {
|
|
return forwarded(f1)(
|
|
forwarded(f2)(
|
|
...
|
|
forwarded(fn)(forwarded(x))
|
|
),
|
|
forwarded(xs)...
|
|
);
|
|
}
|
|
};
|
|
#else
|
|
template <typename F, typename G>
|
|
struct _compose {
|
|
F f; G g;
|
|
|
|
template <typename X, typename ...Xs>
|
|
constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) const& {
|
|
return f(
|
|
g(static_cast<X&&>(x)),
|
|
static_cast<Xs&&>(xs)...
|
|
);
|
|
}
|
|
|
|
template <typename X, typename ...Xs>
|
|
constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) & {
|
|
return f(
|
|
g(static_cast<X&&>(x)),
|
|
static_cast<Xs&&>(xs)...
|
|
);
|
|
}
|
|
|
|
template <typename X, typename ...Xs>
|
|
constexpr decltype(auto) operator()(X&& x, Xs&& ...xs) && {
|
|
return std::move(f)(
|
|
std::move(g)(static_cast<X&&>(x)),
|
|
static_cast<Xs&&>(xs)...
|
|
);
|
|
}
|
|
};
|
|
|
|
struct _make_compose {
|
|
template <typename F, typename G, typename ...H>
|
|
constexpr decltype(auto) operator()(F&& f, G&& g, H&& ...h) const {
|
|
return detail::variadic::foldl1(detail::create<_compose>{},
|
|
static_cast<F&&>(f),
|
|
static_cast<G&&>(g),
|
|
static_cast<H&&>(h)...
|
|
);
|
|
}
|
|
};
|
|
|
|
constexpr _make_compose compose{};
|
|
#endif
|
|
BOOST_HANA_NAMESPACE_END
|
|
|
|
#endif // !BOOST_HANA_FUNCTIONAL_COMPOSE_HPP
|