1 /*! 2 @file 3 Defines `boost::hana::_`. 4 5 @copyright Louis Dionne 2013-2017 6 Distributed under the Boost Software License, Version 1.0. 7 (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) 8 */ 9 10 #ifndef BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP 11 #define BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP 12 13 #include <boost/hana/basic_tuple.hpp> 14 #include <boost/hana/config.hpp> 15 #include <boost/hana/detail/create.hpp> 16 #include <boost/hana/detail/decay.hpp> 17 18 #include <cstddef> 19 #include <utility> 20 21 22 BOOST_HANA_NAMESPACE_BEGIN 23 //! @ingroup group-functional 24 //! Create simple functions representing C++ operators inline. 25 //! 26 //! Specifically, `_` is an object used as a placeholder to build 27 //! function objects representing calls to C++ operators. It works 28 //! by overloading the operators between `_` and any object so that 29 //! they return a function object which actually calls the corresponding 30 //! operator on its argument(s). Hence, for any supported operator `@`: 31 //! @code 32 //! (_ @ _)(x, y) == x @ y 33 //! @endcode 34 //! 35 //! Operators may also be partially applied to one argument inline: 36 //! @code 37 //! (x @ _)(y) == x @ y 38 //! (_ @ y)(x) == x @ y 39 //! @endcode 40 //! 41 //! When invoked with more arguments than required, functions created with 42 //! `_` will discard the superfluous instead of triggering an error: 43 //! @code 44 //! (_ @ _)(x, y, z...) == x @ y 45 //! @endcode 46 //! 47 //! This makes functions created with `_` easier to use in higher-order 48 //! algorithms, which sometime provide more information than necessary 49 //! to their callbacks. 50 //! 51 //! ### Supported operators 52 //! - Arithmetic: binary `+`, binary `-`, `/`, `*`, `%`, unary `+`, unary `-` 53 //! - Bitwise: `~`, `&`, `|`, `^`, `<<`, `>>` 54 //! - Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=` 55 //! - %Logical: `||`, `&&`, `!` 56 //! - Member access: `*` (dereference), `[]` (array subscript) 57 //! - Other: `()` (function call) 58 //! 59 //! More complex functionality like the ability to compose placeholders 60 //! into larger function objects inline are not supported. This is on 61 //! purpose; you should either use C++14 generic lambdas or a library 62 //! like [Boost.Phoenix][] if you need bigger guns. The goal here is 63 //! to save you a couple of characters in simple situations. 64 //! 65 //! ### Example 66 //! @include example/functional/placeholder.cpp 67 //! 68 //! [Boost.Phoenix]: http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html 69 #ifdef BOOST_HANA_DOXYGEN_INVOKED 70 constexpr unspecified _{}; 71 #else 72 namespace placeholder_detail { 73 template <typename I> 74 struct subscript { 75 I i; 76 77 template <typename Xs, typename ...Z> 78 constexpr auto operator()(Xs&& xs, Z const& ...) const& 79 -> decltype(static_cast<Xs&&>(xs)[i]) 80 { return static_cast<Xs&&>(xs)[i]; } 81 82 template <typename Xs, typename ...Z> 83 constexpr auto operator()(Xs&& xs, Z const& ...) & 84 -> decltype(static_cast<Xs&&>(xs)[i]) 85 { return static_cast<Xs&&>(xs)[i]; } 86 87 template <typename Xs, typename ...Z> 88 constexpr auto operator()(Xs&& xs, Z const& ...) && 89 -> decltype(static_cast<Xs&&>(xs)[std::declval<I>()]) 90 { return static_cast<Xs&&>(xs)[std::move(i)]; } 91 }; 92 93 template <typename F, typename Xs, std::size_t ...i> 94 constexpr decltype(auto) invoke_impl(F&& f, Xs&& xs, std::index_sequence<i...>) { 95 return static_cast<F&&>(f)(hana::at_c<i>(static_cast<Xs&&>(xs).storage_)...); 96 } 97 98 template <typename ...X> 99 struct invoke; 100 101 struct placeholder { 102 struct secret { }; 103 104 template <typename X> 105 constexpr decltype(auto) operator[](X&& x) const 106 { return detail::create<subscript>{}(static_cast<X&&>(x)); } 107 108 template <typename ...X> 109 constexpr invoke<typename detail::decay<X>::type...> 110 operator()(X&& ...x) const { 111 return {secret{}, static_cast<X&&>(x)...}; 112 } 113 }; 114 115 template <typename ...X> 116 struct invoke { 117 template <typename ...Y> 118 constexpr invoke(placeholder::secret, Y&& ...y) 119 : storage_{static_cast<Y&&>(y)...} 120 { } 121 122 basic_tuple<X...> storage_; 123 124 template <typename F, typename ...Z> 125 constexpr auto operator()(F&& f, Z const& ...) const& -> decltype( 126 static_cast<F&&>(f)(std::declval<X const&>()...) 127 ) { 128 return invoke_impl(static_cast<F&&>(f), *this, 129 std::make_index_sequence<sizeof...(X)>{}); 130 } 131 132 template <typename F, typename ...Z> 133 constexpr auto operator()(F&& f, Z const& ...) & -> decltype( 134 static_cast<F&&>(f)(std::declval<X&>()...) 135 ) { 136 return invoke_impl(static_cast<F&&>(f), *this, 137 std::make_index_sequence<sizeof...(X)>{}); 138 } 139 140 template <typename F, typename ...Z> 141 constexpr auto operator()(F&& f, Z const& ...) && -> decltype( 142 static_cast<F&&>(f)(std::declval<X&&>()...) 143 ) { 144 return invoke_impl(static_cast<F&&>(f), static_cast<invoke&&>(*this), 145 std::make_index_sequence<sizeof...(X)>{}); 146 } 147 }; 148 149 #define BOOST_HANA_PLACEHOLDER_BINARY_OP(op, op_name) \ 150 template <typename X> \ 151 struct op_name ## _left { \ 152 X x; \ 153 \ 154 template <typename Y, typename ...Z> \ 155 constexpr auto operator()(Y&& y, Z const& ...) const& -> decltype( \ 156 std::declval<X const&>() op static_cast<Y&&>(y)) \ 157 { return x op static_cast<Y&&>(y); } \ 158 \ 159 template <typename Y, typename ...Z> \ 160 constexpr auto operator()(Y&& y, Z const& ...) & -> decltype( \ 161 std::declval<X&>() op static_cast<Y&&>(y)) \ 162 { return x op static_cast<Y&&>(y); } \ 163 \ 164 template <typename Y, typename ...Z> \ 165 constexpr auto operator()(Y&& y, Z const& ...) && -> decltype( \ 166 std::declval<X>() op static_cast<Y&&>(y)) \ 167 { return std::move(x) op static_cast<Y&&>(y); } \ 168 }; \ 169 \ 170 template <typename Y> \ 171 struct op_name ## _right { \ 172 Y y; \ 173 \ 174 template <typename X, typename ...Z> \ 175 constexpr auto operator()(X&& x, Z const& ...) const& -> decltype( \ 176 static_cast<X&&>(x) op std::declval<Y const&>()) \ 177 { return static_cast<X&&>(x) op y; } \ 178 \ 179 template <typename X, typename ...Z> \ 180 constexpr auto operator()(X&& x, Z const& ...) & -> decltype( \ 181 static_cast<X&&>(x) op std::declval<Y&>()) \ 182 { return static_cast<X&&>(x) op y; } \ 183 \ 184 template <typename X, typename ...Z> \ 185 constexpr auto operator()(X&& x, Z const& ...) && -> decltype( \ 186 static_cast<X&&>(x) op std::declval<Y>()) \ 187 { return static_cast<X&&>(x) op std::move(y); } \ 188 }; \ 189 \ 190 struct op_name { \ 191 template <typename X, typename Y, typename ...Z> \ 192 constexpr auto operator()(X&& x, Y&& y, Z const& ...) const -> decltype(\ 193 static_cast<X&&>(x) op static_cast<Y&&>(y)) \ 194 { return static_cast<X&&>(x) op static_cast<Y&&>(y); } \ 195 }; \ 196 \ 197 template <typename X> \ 198 constexpr decltype(auto) operator op (X&& x, placeholder) \ 199 { return detail::create<op_name ## _left>{}(static_cast<X&&>(x)); } \ 200 \ 201 template <typename Y> \ 202 constexpr decltype(auto) operator op (placeholder, Y&& y) \ 203 { return detail::create<op_name ## _right>{}(static_cast<Y&&>(y)); } \ 204 \ 205 inline constexpr decltype(auto) operator op (placeholder, placeholder) \ 206 { return op_name{}; } \ 207 /**/ 208 209 #define BOOST_HANA_PLACEHOLDER_UNARY_OP(op, op_name) \ 210 struct op_name { \ 211 template <typename X, typename ...Z> \ 212 constexpr auto operator()(X&& x, Z const& ...) const \ 213 -> decltype(op static_cast<X&&>(x)) \ 214 { return op static_cast<X&&>(x); } \ 215 }; \ 216 \ 217 inline constexpr decltype(auto) operator op (placeholder) \ 218 { return op_name{}; } \ 219 /**/ 220 // Arithmetic 221 BOOST_HANA_PLACEHOLDER_UNARY_OP(+, unary_plus) 222 BOOST_HANA_PLACEHOLDER_UNARY_OP(-, unary_minus) 223 BOOST_HANA_PLACEHOLDER_BINARY_OP(+, plus) 224 BOOST_HANA_PLACEHOLDER_BINARY_OP(-, minus) 225 BOOST_HANA_PLACEHOLDER_BINARY_OP(*, times) 226 BOOST_HANA_PLACEHOLDER_BINARY_OP(/, divide) 227 BOOST_HANA_PLACEHOLDER_BINARY_OP(%, modulo) 228 229 // Bitwise 230 BOOST_HANA_PLACEHOLDER_UNARY_OP(~, bitwise_not) 231 BOOST_HANA_PLACEHOLDER_BINARY_OP(&, bitwise_and) 232 BOOST_HANA_PLACEHOLDER_BINARY_OP(|, bitwise_or) 233 BOOST_HANA_PLACEHOLDER_BINARY_OP(^, bitwise_xor) 234 BOOST_HANA_PLACEHOLDER_BINARY_OP(<<, left_shift) 235 BOOST_HANA_PLACEHOLDER_BINARY_OP(>>, right_shift) 236 237 // Comparison 238 BOOST_HANA_PLACEHOLDER_BINARY_OP(==, equal) 239 BOOST_HANA_PLACEHOLDER_BINARY_OP(!=, not_equal) 240 BOOST_HANA_PLACEHOLDER_BINARY_OP(<, less) 241 BOOST_HANA_PLACEHOLDER_BINARY_OP(<=, less_equal) 242 BOOST_HANA_PLACEHOLDER_BINARY_OP(>, greater) 243 BOOST_HANA_PLACEHOLDER_BINARY_OP(>=, greater_equal) 244 245 // Logical 246 BOOST_HANA_PLACEHOLDER_BINARY_OP(||, logical_or) 247 BOOST_HANA_PLACEHOLDER_BINARY_OP(&&, logical_and) 248 BOOST_HANA_PLACEHOLDER_UNARY_OP(!, logical_not) 249 250 // Member access (array subscript is a member function) 251 BOOST_HANA_PLACEHOLDER_UNARY_OP(*, dereference) 252 253 // Other (function call is a member function) 254 255 #undef BOOST_HANA_PREFIX_PLACEHOLDER_OP 256 #undef BOOST_HANA_BINARY_PLACEHOLDER_OP 257 } // end namespace placeholder_detail 258 259 constexpr placeholder_detail::placeholder _{}; 260 #endif 261 BOOST_HANA_NAMESPACE_END 262 263 #endif // !BOOST_HANA_FUNCTIONAL_PLACEHOLDER_HPP 264