]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*! |
2 | @file | |
3 | Defines `boost::hana::_`. | |
4 | ||
5 | @copyright Louis Dionne 2013-2016 | |
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::get_impl<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 |