123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263 |
- /*!
- @file
- Defines `boost::hana::_`.
- @copyright Louis Dionne 2013-2017
- 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_PLACEHOLDER_HPP
- #define BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
- #include <boost/hana/basic_tuple.hpp>
- #include <boost/hana/config.hpp>
- #include <boost/hana/detail/create.hpp>
- #include <boost/hana/detail/decay.hpp>
- #include <cstddef>
- #include <utility>
- BOOST_HANA_NAMESPACE_BEGIN
- //! @ingroup group-functional
- //! Create simple functions representing C++ operators inline.
- //!
- //! Specifically, `_` is an object used as a placeholder to build
- //! function objects representing calls to C++ operators. It works
- //! by overloading the operators between `_` and any object so that
- //! they return a function object which actually calls the corresponding
- //! operator on its argument(s). Hence, for any supported operator `@`:
- //! @code
- //! (_ @ _)(x, y) == x @ y
- //! @endcode
- //!
- //! Operators may also be partially applied to one argument inline:
- //! @code
- //! (x @ _)(y) == x @ y
- //! (_ @ y)(x) == x @ y
- //! @endcode
- //!
- //! When invoked with more arguments than required, functions created with
- //! `_` will discard the superfluous instead of triggering an error:
- //! @code
- //! (_ @ _)(x, y, z...) == x @ y
- //! @endcode
- //!
- //! This makes functions created with `_` easier to use in higher-order
- //! algorithms, which sometime provide more information than necessary
- //! to their callbacks.
- //!
- //! ### Supported operators
- //! - Arithmetic: binary `+`, binary `-`, `/`, `*`, `%`, unary `+`, unary `-`
- //! - Bitwise: `~`, `&`, `|`, `^`, `<<`, `>>`
- //! - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`
- //! - %Logical: `||`, `&&`, `!`
- //! - Member access: `*` (dereference), `[]` (array subscript)
- //! - Other: `()` (function call)
- //!
- //! More complex functionality like the ability to compose placeholders
- //! into larger function objects inline are not supported. This is on
- //! purpose; you should either use C++14 generic lambdas or a library
- //! like [Boost.Phoenix][] if you need bigger guns. The goal here is
- //! to save you a couple of characters in simple situations.
- //!
- //! ### Example
- //! @include example/functional/placeholder.cpp
- //!
- //! [Boost.Phoenix]: http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html
- #ifdef BOOST_HANA_DOXYGEN_INVOKED
- constexpr unspecified _{};
- #else
- namespace placeholder_detail {
- template <typename I>
- struct subscript {
- I i;
- template <typename Xs, typename ...Z>
- constexpr auto operator()(Xs&& xs, Z const& ...) const&
- -> decltype(static_cast<Xs&&>(xs)[i])
- { return static_cast<Xs&&>(xs)[i]; }
- template <typename Xs, typename ...Z>
- constexpr auto operator()(Xs&& xs, Z const& ...) &
- -> decltype(static_cast<Xs&&>(xs)[i])
- { return static_cast<Xs&&>(xs)[i]; }
- template <typename Xs, typename ...Z>
- constexpr auto operator()(Xs&& xs, Z const& ...) &&
- -> decltype(static_cast<Xs&&>(xs)[std::declval<I>()])
- { return static_cast<Xs&&>(xs)[std::move(i)]; }
- };
- template <typename F, typename Xs, std::size_t ...i>
- constexpr decltype(auto) invoke_impl(F&& f, Xs&& xs, std::index_sequence<i...>) {
- return static_cast<F&&>(f)(hana::at_c<i>(static_cast<Xs&&>(xs).storage_)...);
- }
- template <typename ...X>
- struct invoke;
- struct placeholder {
- struct secret { };
- template <typename X>
- constexpr decltype(auto) operator[](X&& x) const
- { return detail::create<subscript>{}(static_cast<X&&>(x)); }
- template <typename ...X>
- constexpr invoke<typename detail::decay<X>::type...>
- operator()(X&& ...x) const {
- return {secret{}, static_cast<X&&>(x)...};
- }
- };
- template <typename ...X>
- struct invoke {
- template <typename ...Y>
- constexpr invoke(placeholder::secret, Y&& ...y)
- : storage_{static_cast<Y&&>(y)...}
- { }
- basic_tuple<X...> storage_;
- template <typename F, typename ...Z>
- constexpr auto operator()(F&& f, Z const& ...) const& -> decltype(
- static_cast<F&&>(f)(std::declval<X const&>()...)
- ) {
- return invoke_impl(static_cast<F&&>(f), *this,
- std::make_index_sequence<sizeof...(X)>{});
- }
- template <typename F, typename ...Z>
- constexpr auto operator()(F&& f, Z const& ...) & -> decltype(
- static_cast<F&&>(f)(std::declval<X&>()...)
- ) {
- return invoke_impl(static_cast<F&&>(f), *this,
- std::make_index_sequence<sizeof...(X)>{});
- }
- template <typename F, typename ...Z>
- constexpr auto operator()(F&& f, Z const& ...) && -> decltype(
- static_cast<F&&>(f)(std::declval<X&&>()...)
- ) {
- return invoke_impl(static_cast<F&&>(f), static_cast<invoke&&>(*this),
- std::make_index_sequence<sizeof...(X)>{});
- }
- };
- #define BOOST_HANA_PLACEHOLDER_BINARY_OP(op, op_name) \
- template <typename X> \
- struct op_name ## _left { \
- X x; \
- \
- template <typename Y, typename ...Z> \
- constexpr auto operator()(Y&& y, Z const& ...) const& -> decltype( \
- std::declval<X const&>() op static_cast<Y&&>(y)) \
- { return x op static_cast<Y&&>(y); } \
- \
- template <typename Y, typename ...Z> \
- constexpr auto operator()(Y&& y, Z const& ...) & -> decltype( \
- std::declval<X&>() op static_cast<Y&&>(y)) \
- { return x op static_cast<Y&&>(y); } \
- \
- template <typename Y, typename ...Z> \
- constexpr auto operator()(Y&& y, Z const& ...) && -> decltype( \
- std::declval<X>() op static_cast<Y&&>(y)) \
- { return std::move(x) op static_cast<Y&&>(y); } \
- }; \
- \
- template <typename Y> \
- struct op_name ## _right { \
- Y y; \
- \
- template <typename X, typename ...Z> \
- constexpr auto operator()(X&& x, Z const& ...) const& -> decltype( \
- static_cast<X&&>(x) op std::declval<Y const&>()) \
- { return static_cast<X&&>(x) op y; } \
- \
- template <typename X, typename ...Z> \
- constexpr auto operator()(X&& x, Z const& ...) & -> decltype( \
- static_cast<X&&>(x) op std::declval<Y&>()) \
- { return static_cast<X&&>(x) op y; } \
- \
- template <typename X, typename ...Z> \
- constexpr auto operator()(X&& x, Z const& ...) && -> decltype( \
- static_cast<X&&>(x) op std::declval<Y>()) \
- { return static_cast<X&&>(x) op std::move(y); } \
- }; \
- \
- struct op_name { \
- template <typename X, typename Y, typename ...Z> \
- constexpr auto operator()(X&& x, Y&& y, Z const& ...) const -> decltype(\
- static_cast<X&&>(x) op static_cast<Y&&>(y)) \
- { return static_cast<X&&>(x) op static_cast<Y&&>(y); } \
- }; \
- \
- template <typename X> \
- constexpr decltype(auto) operator op (X&& x, placeholder) \
- { return detail::create<op_name ## _left>{}(static_cast<X&&>(x)); } \
- \
- template <typename Y> \
- constexpr decltype(auto) operator op (placeholder, Y&& y) \
- { return detail::create<op_name ## _right>{}(static_cast<Y&&>(y)); } \
- \
- inline constexpr decltype(auto) operator op (placeholder, placeholder) \
- { return op_name{}; } \
- /**/
- #define BOOST_HANA_PLACEHOLDER_UNARY_OP(op, op_name) \
- struct op_name { \
- template <typename X, typename ...Z> \
- constexpr auto operator()(X&& x, Z const& ...) const \
- -> decltype(op static_cast<X&&>(x)) \
- { return op static_cast<X&&>(x); } \
- }; \
- \
- inline constexpr decltype(auto) operator op (placeholder) \
- { return op_name{}; } \
- /**/
- // Arithmetic
- BOOST_HANA_PLACEHOLDER_UNARY_OP(+, unary_plus)
- BOOST_HANA_PLACEHOLDER_UNARY_OP(-, unary_minus)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(+, plus)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(-, minus)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(*, times)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(/, divide)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(%, modulo)
- // Bitwise
- BOOST_HANA_PLACEHOLDER_UNARY_OP(~, bitwise_not)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(&, bitwise_and)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(|, bitwise_or)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(^, bitwise_xor)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(<<, left_shift)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(>>, right_shift)
- // Comparison
- BOOST_HANA_PLACEHOLDER_BINARY_OP(==, equal)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(!=, not_equal)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(<, less)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(<=, less_equal)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(>, greater)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(>=, greater_equal)
- // Logical
- BOOST_HANA_PLACEHOLDER_BINARY_OP(||, logical_or)
- BOOST_HANA_PLACEHOLDER_BINARY_OP(&&, logical_and)
- BOOST_HANA_PLACEHOLDER_UNARY_OP(!, logical_not)
- // Member access (array subscript is a member function)
- BOOST_HANA_PLACEHOLDER_UNARY_OP(*, dereference)
- // Other (function call is a member function)
- #undef BOOST_HANA_PREFIX_PLACEHOLDER_OP
- #undef BOOST_HANA_BINARY_PLACEHOLDER_OP
- } // end namespace placeholder_detail
- constexpr placeholder_detail::placeholder _{};
- #endif
- BOOST_HANA_NAMESPACE_END
- #endif // !BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP
|