| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 | /*!@fileDefines `boost::hana::infix`.@copyright Louis Dionne 2013-2017Distributed 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_INFIX_HPP#define BOOST_HANA_FUNCTIONAL_INFIX_HPP#include <boost/hana/config.hpp>#include <boost/hana/detail/decay.hpp>#include <boost/hana/functional/partial.hpp>#include <boost/hana/functional/reverse_partial.hpp>#include <type_traits>#include <utility>BOOST_HANA_NAMESPACE_BEGIN    //! @ingroup group-functional    //! Return an equivalent function that can also be applied in infix    //! notation.    //!    //! Specifically, `infix(f)` is an object such that:    //! @code    //!     infix(f)(x1, ..., xn) == f(x1, ..., xn)    //!     x ^infix(f)^ y == f(x, y)    //! @endcode    //!    //! Hence, the returned function can still be applied using the usual    //! function call syntax, but it also gains the ability to be applied in    //! infix notation. The infix syntax allows a great deal of expressiveness,    //! especially when used in combination with some higher order algorithms.    //! Since `operator^` is left-associative, `x ^infix(f)^ y` is actually    //! parsed as `(x ^infix(f))^ y`. However, for flexibility, the order in    //! which both arguments are applied in infix notation does not matter.    //! Hence, it is always the case that    //! @code    //!     (x ^ infix(f)) ^ y == x ^ (infix(f) ^ y)    //! @endcode    //!    //! However, note that applying more than one argument in infix    //! notation to the same side of the operator will result in a    //! compile-time assertion:    //! @code    //!     (infix(f) ^ x) ^ y; // compile-time assertion    //!     y ^ (x ^ infix(f)); // compile-time assertion    //! @endcode    //!    //! Additionally, a function created with `infix` may be partially applied    //! in infix notation. Specifically,    //! @code    //!     (x ^ infix(f))(y1, ..., yn) == f(x, y1, ..., yn)    //!     (infix(f) ^ y)(x1, ..., xn) == f(x1, ..., xn, y)    //! @endcode    //!    //! @internal    //! ### Rationales    //! 1. The `^` operator was chosen because it is left-associative and    //!    has a low enough priority so that most expressions will render    //!    the expected behavior.    //! 2. The operator can't be customimzed because that would require more    //!    sophistication in the implementation; I want to keep it as simple    //!    as possible. There is also an advantage in having a uniform syntax    //!    for infix application.    //! @endinternal    //!    //! @param f    //! The function which gains the ability to be applied in infix notation.    //! The function must be at least binary; a compile-time error will be    //! triggered otherwise.    //!    //! ### Example    //! @include example/functional/infix.cpp#ifdef BOOST_HANA_DOXYGEN_INVOKED    constexpr auto infix = [](auto f) {        return unspecified;    };#else    namespace infix_detail {        // This needs to be in the same namespace as `operator^` so it can be        // found by ADL.        template <bool left, bool right, typename F>        struct infix_t {            F f;            template <typename ...X>            constexpr decltype(auto) operator()(X&& ...x) const&            { return f(static_cast<X&&>(x)...); }            template <typename ...X>            constexpr decltype(auto) operator()(X&& ...x) &            { return f(static_cast<X&&>(x)...); }            template <typename ...X>            constexpr decltype(auto) operator()(X&& ...x) &&            { return std::move(f)(static_cast<X&&>(x)...); }        };        template <bool left, bool right>        struct make_infix {            template <typename F>            constexpr infix_t<left, right, typename detail::decay<F>::type>            operator()(F&& f) const { return {static_cast<F&&>(f)}; }        };        template <bool left, bool right>        struct Infix;        struct Object;        template <typename T>        struct dispatch { using type = Object; };        template <bool left, bool right, typename F>        struct dispatch<infix_t<left, right, F>> {            using type = Infix<left, right>;        };        template <typename, typename>        struct bind_infix;        // infix(f) ^ y        template <>        struct bind_infix<Infix<false, false>, Object> {            template <typename F, typename Y>            static constexpr decltype(auto) apply(F&& f, Y&& y) {                return make_infix<false, true>{}(                    hana::reverse_partial(                        static_cast<F&&>(f), static_cast<Y&&>(y)                    )                );            }        };        // (x^infix(f)) ^ y        template <>        struct bind_infix<Infix<true, false>, Object> {            template <typename F, typename Y>            static constexpr decltype(auto) apply(F&& f, Y&& y) {                return static_cast<F&&>(f)(static_cast<Y&&>(y));            }        };        // x ^ infix(f)        template <>        struct bind_infix<Object, Infix<false, false>> {            template <typename X, typename F>            static constexpr decltype(auto) apply(X&& x, F&& f) {                return make_infix<true, false>{}(                    hana::partial(static_cast<F&&>(f), static_cast<X&&>(x))                );            }        };        // x ^ (infix(f)^y)        template <>        struct bind_infix<Object, Infix<false, true>> {            template <typename X, typename F>            static constexpr decltype(auto) apply(X&& x, F&& f) {                return static_cast<F&&>(f)(static_cast<X&&>(x));            }        };        template <typename T>        using strip = typename std::remove_cv<            typename std::remove_reference<T>::type        >::type;        template <typename X, typename Y>        constexpr decltype(auto) operator^(X&& x, Y&& y) {            return bind_infix<                typename dispatch<strip<X>>::type,                typename dispatch<strip<Y>>::type            >::apply(static_cast<X&&>(x), static_cast<Y&&>(y));        }    } // end namespace infix_detail    constexpr infix_detail::make_infix<false, false> infix{};#endifBOOST_HANA_NAMESPACE_END#endif // !BOOST_HANA_FUNCTIONAL_INFIX_HPP
 |