placeholder.hpp 13 KB

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