/*! @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 #include #include #include #include #include namespace boost { namespace hana { //! @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 struct subscript { I i; template constexpr auto operator()(Xs&& xs, Z const& ...) const& -> decltype(static_cast(xs)[i]) { return static_cast(xs)[i]; } template constexpr auto operator()(Xs&& xs, Z const& ...) & -> decltype(static_cast(xs)[i]) { return static_cast(xs)[i]; } template constexpr auto operator()(Xs&& xs, Z const& ...) && -> decltype(static_cast(xs)[std::declval()]) { return static_cast(xs)[std::move(i)]; } }; template constexpr decltype(auto) invoke_impl(F&& f, Xs&& xs, std::index_sequence) { return static_cast(f)(hana::at_c(static_cast(xs).storage_)...); } template struct invoke; struct placeholder { struct secret { }; template constexpr decltype(auto) operator[](X&& x) const { return detail::create{}(static_cast(x)); } template constexpr invoke::type...> operator()(X&& ...x) const { return {secret{}, static_cast(x)...}; } }; template struct invoke { template constexpr invoke(placeholder::secret, Y&& ...y) : storage_{static_cast(y)...} { } basic_tuple storage_; template constexpr auto operator()(F&& f, Z const& ...) const& -> decltype( static_cast(f)(std::declval()...) ) { return invoke_impl(static_cast(f), *this, std::make_index_sequence{}); } template constexpr auto operator()(F&& f, Z const& ...) & -> decltype( static_cast(f)(std::declval()...) ) { return invoke_impl(static_cast(f), *this, std::make_index_sequence{}); } template constexpr auto operator()(F&& f, Z const& ...) && -> decltype( static_cast(f)(std::declval()...) ) { return invoke_impl(static_cast(f), static_cast(*this), std::make_index_sequence{}); } }; #define BOOST_HANA_PLACEHOLDER_BINARY_OP(op, op_name) \ template \ struct op_name ## _left { \ X x; \ \ template \ constexpr auto operator()(Y&& y, Z const& ...) const& -> decltype( \ std::declval() op static_cast(y)) \ { return x op static_cast(y); } \ \ template \ constexpr auto operator()(Y&& y, Z const& ...) & -> decltype( \ std::declval() op static_cast(y)) \ { return x op static_cast(y); } \ \ template \ constexpr auto operator()(Y&& y, Z const& ...) && -> decltype( \ std::declval() op static_cast(y)) \ { return std::move(x) op static_cast(y); } \ }; \ \ template \ struct op_name ## _right { \ Y y; \ \ template \ constexpr auto operator()(X&& x, Z const& ...) const& -> decltype( \ static_cast(x) op std::declval()) \ { return static_cast(x) op y; } \ \ template \ constexpr auto operator()(X&& x, Z const& ...) & -> decltype( \ static_cast(x) op std::declval()) \ { return static_cast(x) op y; } \ \ template \ constexpr auto operator()(X&& x, Z const& ...) && -> decltype( \ static_cast(x) op std::declval()) \ { return static_cast(x) op std::move(y); } \ }; \ \ struct op_name { \ template \ constexpr auto operator()(X&& x, Y&& y, Z const& ...) const -> decltype(\ static_cast(x) op static_cast(y)) \ { return static_cast(x) op static_cast(y); } \ }; \ \ template \ constexpr decltype(auto) operator op (X&& x, placeholder) \ { return detail::create{}(static_cast(x)); } \ \ template \ constexpr decltype(auto) operator op (placeholder, Y&& y) \ { return detail::create{}(static_cast(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 \ constexpr auto operator()(X&& x, Z const& ...) const \ -> decltype(op static_cast(x)) \ { return op static_cast(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 BOOST_HANA_INLINE_VARIABLE constexpr placeholder_detail::placeholder _{}; #endif }} // end namespace boost::hana #endif // !BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP