• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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