placeholders.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. /*=============================================================================
  2. Copyright (c) 2014 Paul Fultz II
  3. placeholders.h
  4. Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. ==============================================================================*/
  7. #ifndef BOOST_HOF_GUARD_FUNCTION_PLACEHOLDERS_H
  8. #define BOOST_HOF_GUARD_FUNCTION_PLACEHOLDERS_H
  9. /// placeholders
  10. /// ============
  11. ///
  12. /// Description
  13. /// -----------
  14. ///
  15. /// The placeholders provide `std::bind` compatible placeholders that
  16. /// additionally provide basic C++ operators that creates bind expressions.
  17. /// Each bind expression supports `constexpr` function evaluation.
  18. ///
  19. /// Synopsis
  20. /// --------
  21. ///
  22. /// namespace placeholders {
  23. /// placeholder<1> _1 = {};
  24. /// placeholder<2> _2 = {};
  25. /// placeholder<3> _3 = {};
  26. /// placeholder<4> _4 = {};
  27. /// placeholder<5> _5 = {};
  28. /// placeholder<6> _6 = {};
  29. /// placeholder<7> _7 = {};
  30. /// placeholder<8> _8 = {};
  31. /// placeholder<9> _9 = {};
  32. /// }
  33. ///
  34. /// Operators
  35. /// ---------
  36. ///
  37. /// * Binary operators: +,-,*,/,%,>>,<<,>,<,<=,>=,==,!=,&,^,|,&&,||
  38. /// * Assign operators: +=,-=,*=,/=,%=,>>=,<<=,&=,|=,^=
  39. /// * Unary operators: !,~,+,-,*,++,--
  40. ///
  41. ///
  42. /// Example
  43. /// -------
  44. ///
  45. /// #include <boost/hof.hpp>
  46. /// #include <cassert>
  47. /// using namespace boost::hof;
  48. ///
  49. /// int main() {
  50. /// auto sum = _1 + _2;
  51. /// assert(3 == sum(1, 2));
  52. /// }
  53. ///
  54. ///
  55. /// unamed placeholder
  56. /// ==================
  57. ///
  58. /// Description
  59. /// -----------
  60. ///
  61. /// The unamed placeholder can be used to build simple functions from C++
  62. /// operators.
  63. ///
  64. /// Note: The function produced by the unamed placeholder is not a bind expression.
  65. ///
  66. /// Synopsis
  67. /// --------
  68. ///
  69. /// namespace placeholders {
  70. /// /* unspecified */ _ = {};
  71. /// }
  72. ///
  73. /// Example
  74. /// -------
  75. ///
  76. /// #include <boost/hof.hpp>
  77. /// #include <cassert>
  78. /// using namespace boost::hof;
  79. ///
  80. /// int main() {
  81. /// auto sum = _ + _;
  82. /// assert(3 == sum(1, 2));
  83. /// }
  84. ///
  85. #include <boost/hof/returns.hpp>
  86. #include <boost/hof/lazy.hpp>
  87. #include <boost/hof/protect.hpp>
  88. #if defined(_MSC_VER) && _MSC_VER >= 1910
  89. #include <boost/hof/detail/pp.hpp>
  90. #endif
  91. namespace boost { namespace hof { namespace detail {
  92. template<int N>
  93. struct simple_placeholder
  94. {};
  95. }}} // namespace boost::hof
  96. namespace std {
  97. template<int N>
  98. struct is_placeholder<boost::hof::detail::simple_placeholder<N>>
  99. : std::integral_constant<int, N>
  100. {};
  101. }
  102. namespace boost { namespace hof {
  103. #define BOOST_HOF_FOREACH_BINARY_OP(m) \
  104. m(+, add) \
  105. m(-, subtract) \
  106. m(*, multiply) \
  107. m(/, divide) \
  108. m(%, remainder) \
  109. m(>>, shift_right) \
  110. m(<<, shift_left) \
  111. m(>, greater_than) \
  112. m(<, less_than) \
  113. m(<=, less_than_equal) \
  114. m(>=, greater_than_equal) \
  115. m(==, equal) \
  116. m(!=, not_equal) \
  117. m(&, bit_and) \
  118. m(^, xor_) \
  119. m(|, bit_or) \
  120. m(&&, and_) \
  121. m(||, or_)
  122. #define BOOST_HOF_FOREACH_ASSIGN_OP(m) \
  123. m(+=, assign_add) \
  124. m(-=, assign_subtract) \
  125. m(*=, assign_multiply) \
  126. m(/=, assign_divide) \
  127. m(%=, assign_remainder) \
  128. m(>>=, assign_right_shift) \
  129. m(<<=, assign_left_shift) \
  130. m(&=, assign_bit_and) \
  131. m(|=, assign_bit_or) \
  132. m(^=, assign_xor)
  133. #ifndef _MSC_VER
  134. #define BOOST_HOF_FOREACH_UNARY_OP(m) \
  135. m(!, not_) \
  136. m(~, compl_) \
  137. m(+, unary_plus) \
  138. m(-, unary_subtract) \
  139. m(*, dereference) \
  140. m(++, increment) \
  141. m(--, decrement)
  142. #else
  143. #define BOOST_HOF_FOREACH_UNARY_OP(m) \
  144. m(!, not_) \
  145. m(~, compl_) \
  146. m(+, unary_plus) \
  147. m(-, unary_subtract) \
  148. m(*, dereference)
  149. #endif
  150. namespace operators {
  151. struct call
  152. {
  153. template<class F, class... Ts>
  154. constexpr auto operator()(F&& f, Ts&&... xs) const BOOST_HOF_RETURNS
  155. (f(BOOST_HOF_FORWARD(Ts)(xs)...));
  156. };
  157. // MSVC 2017 ICEs on && and || in conxtexpr, so we fallback on bitwise operators
  158. #if defined(_MSC_VER) && _MSC_VER >= 1910
  159. #define BOOST_HOF_BINARY_OP_SKIP_and_ ()
  160. #define BOOST_HOF_BINARY_OP_SKIP_or_ ()
  161. struct and_
  162. {
  163. template<class T, class U>
  164. constexpr auto operator()(T&& x, U&& y) const
  165. noexcept(noexcept(BOOST_HOF_FORWARD(T)(x) && BOOST_HOF_FORWARD(U)(y)))
  166. -> decltype(BOOST_HOF_FORWARD(T)(x) && BOOST_HOF_FORWARD(U)(y))
  167. { return BOOST_HOF_FORWARD(T)(x) & BOOST_HOF_FORWARD(U)(y); }
  168. };
  169. struct or_
  170. {
  171. template<class T, class U>
  172. constexpr auto operator()(T&& x, U&& y) const
  173. noexcept(noexcept(BOOST_HOF_FORWARD(T)(x) || BOOST_HOF_FORWARD(U)(y)))
  174. -> decltype(BOOST_HOF_FORWARD(T)(x) || BOOST_HOF_FORWARD(U)(y))
  175. { return BOOST_HOF_FORWARD(T)(x) | BOOST_HOF_FORWARD(U)(y); }
  176. };
  177. #define BOOST_HOF_BINARY_OP_IMPL(op, name) \
  178. struct name \
  179. { \
  180. template<class T, class U> \
  181. BOOST_HOF_USING(ex_failure, decltype(std::declval<T>() op std::declval<U>())); \
  182. struct failure : as_failure<ex_failure> {}; \
  183. template<class T, class U> \
  184. constexpr auto operator()(T&& x, U&& y) const BOOST_HOF_RETURNS \
  185. (BOOST_HOF_FORWARD(T)(x) op BOOST_HOF_FORWARD(U)(y)); \
  186. };
  187. #define BOOST_HOF_BINARY_OP(op, name) \
  188. BOOST_HOF_PP_IIF(BOOST_HOF_PP_IS_PAREN(BOOST_HOF_PP_CAT(BOOST_HOF_BINARY_OP_SKIP_, name))) \
  189. (BOOST_HOF_PP_EMPTY, BOOST_HOF_BINARY_OP_IMPL)(op, name)
  190. #else
  191. #define BOOST_HOF_BINARY_OP(op, name) \
  192. struct name \
  193. { \
  194. template<class T, class U> \
  195. constexpr auto operator()(T&& x, U&& y) const BOOST_HOF_RETURNS \
  196. (BOOST_HOF_FORWARD(T)(x) op BOOST_HOF_FORWARD(U)(y)); \
  197. };
  198. #endif
  199. BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_BINARY_OP)
  200. BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_BINARY_OP)
  201. #define BOOST_HOF_UNARY_OP(op, name) \
  202. struct name \
  203. { \
  204. template<class T> \
  205. constexpr auto operator()(T&& x) const BOOST_HOF_RETURNS \
  206. (op(BOOST_HOF_FORWARD(T)(x))); \
  207. };
  208. BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_UNARY_OP)
  209. }
  210. template<int N>
  211. struct placeholder
  212. {
  213. #if BOOST_HOF_HAS_MANGLE_OVERLOAD
  214. template<class... Ts>
  215. constexpr auto operator()(Ts&&... xs) const BOOST_HOF_RETURNS
  216. ( boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(Ts)(xs)...) );
  217. #else
  218. template<class... Ts>
  219. struct result_call
  220. { typedef decltype(boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), std::declval<Ts>()...)) type; };
  221. template<class... Ts>
  222. constexpr typename result_call<Ts...>::type operator()(Ts&&... xs) const
  223. { return boost::hof::lazy(operators::call())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(Ts)(xs)...); };
  224. #endif
  225. #define BOOST_HOF_PLACEHOLDER_UNARY_OP(op, name) \
  226. constexpr auto operator op () const BOOST_HOF_RETURNS \
  227. ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>()) );
  228. BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_PLACEHOLDER_UNARY_OP)
  229. #define BOOST_HOF_PLACEHOLDER_ASSIGN_OP(op, name) \
  230. template<class T> \
  231. constexpr auto operator op (T&& x) const BOOST_HOF_RETURNS \
  232. ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)) );
  233. BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_PLACEHOLDER_ASSIGN_OP)
  234. };
  235. #if BOOST_HOF_HAS_MANGLE_OVERLOAD
  236. #define BOOST_HOF_PLACEHOLDER_BINARY_OP(op, name) \
  237. template<class T, int N> \
  238. constexpr inline auto operator op (const placeholder<N>&, T&& x) BOOST_HOF_RETURNS \
  239. ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)) ); \
  240. template<class T, int N> \
  241. constexpr inline auto operator op (T&& x, const placeholder<N>&) BOOST_HOF_RETURNS \
  242. ( boost::hof::lazy(operators::name())(BOOST_HOF_FORWARD(T)(x), detail::simple_placeholder<N>()) ); \
  243. template<int N, int M> \
  244. constexpr inline auto operator op (const placeholder<N>&, const placeholder<M>&) BOOST_HOF_RETURNS \
  245. ( boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), detail::simple_placeholder<M>()) );
  246. #else
  247. #define BOOST_HOF_PLACEHOLDER_BINARY_OP(op, name) \
  248. template<class T, class U> \
  249. struct result_ ## name \
  250. { typedef decltype(boost::hof::lazy(operators::name())(std::declval<T>(), std::declval<U>())) type; }; \
  251. template<class T, int N> \
  252. constexpr inline typename result_ ## name<detail::simple_placeholder<N>, T>::type operator op (const placeholder<N>&, T&& x) \
  253. { return boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), BOOST_HOF_FORWARD(T)(x)); } \
  254. template<class T, int N> \
  255. constexpr inline typename result_ ## name<T, detail::simple_placeholder<N>>::type operator op (T&& x, const placeholder<N>&) \
  256. { return boost::hof::lazy(operators::name())(BOOST_HOF_FORWARD(T)(x), detail::simple_placeholder<N>()); } \
  257. template<int N, int M> \
  258. constexpr inline typename result_ ## name<detail::simple_placeholder<N>, detail::simple_placeholder<M>>::type operator op (const placeholder<N>&, const placeholder<M>&) \
  259. { return boost::hof::lazy(operators::name())(detail::simple_placeholder<N>(), detail::simple_placeholder<M>()); }
  260. #endif
  261. BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_PLACEHOLDER_BINARY_OP)
  262. namespace placeholders {
  263. BOOST_HOF_DECLARE_STATIC_VAR(_1, placeholder<1>);
  264. BOOST_HOF_DECLARE_STATIC_VAR(_2, placeholder<2>);
  265. BOOST_HOF_DECLARE_STATIC_VAR(_3, placeholder<3>);
  266. BOOST_HOF_DECLARE_STATIC_VAR(_4, placeholder<4>);
  267. BOOST_HOF_DECLARE_STATIC_VAR(_5, placeholder<5>);
  268. BOOST_HOF_DECLARE_STATIC_VAR(_6, placeholder<6>);
  269. BOOST_HOF_DECLARE_STATIC_VAR(_7, placeholder<7>);
  270. BOOST_HOF_DECLARE_STATIC_VAR(_8, placeholder<8>);
  271. BOOST_HOF_DECLARE_STATIC_VAR(_9, placeholder<9>);
  272. }
  273. using placeholders::_1;
  274. using placeholders::_2;
  275. using placeholders::_3;
  276. using placeholders::_4;
  277. using placeholders::_5;
  278. using placeholders::_6;
  279. using placeholders::_7;
  280. using placeholders::_8;
  281. using placeholders::_9;
  282. namespace detail {
  283. struct unamed_placeholder
  284. {
  285. template<class T, class Invoker>
  286. struct partial_ap
  287. {
  288. T val;
  289. BOOST_HOF_INHERIT_DEFAULT_EMPTY(partial_ap, T)
  290. template<class X, class... Xs, BOOST_HOF_ENABLE_IF_CONSTRUCTIBLE(T, X&&, Xs&&...)>
  291. constexpr partial_ap(X&& x, Xs&&... xs) : val(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(Xs)(xs)...)
  292. {}
  293. BOOST_HOF_RETURNS_CLASS(partial_ap);
  294. struct partial_ap_failure
  295. {
  296. template<class Failure>
  297. struct apply
  298. {
  299. template<class... Xs>
  300. struct of;
  301. template<class X>
  302. struct of<X>
  303. : Failure::template of<typename std::add_const<T>::type, X>
  304. {};
  305. };
  306. };
  307. struct failure
  308. : failure_map<partial_ap_failure, Invoker>
  309. {};
  310. template<class X>
  311. constexpr BOOST_HOF_SFINAE_RESULT(const Invoker&, id_<T>, id_<X>)
  312. operator()(X&& x) const BOOST_HOF_SFINAE_RETURNS
  313. (
  314. Invoker()(BOOST_HOF_CONST_THIS->val, BOOST_HOF_FORWARD(X)(x))
  315. );
  316. };
  317. template<class Invoker, class T>
  318. static constexpr partial_ap<T, Invoker> make_partial_ap(T&& x)
  319. {
  320. return {BOOST_HOF_FORWARD(T)(x)};
  321. }
  322. template<class Op>
  323. struct left
  324. {
  325. struct failure
  326. : failure_for<Op>
  327. {};
  328. template<class T, class X>
  329. constexpr BOOST_HOF_SFINAE_RESULT(const Op&, id_<T>, id_<X>)
  330. operator()(T&& val, X&& x) const BOOST_HOF_SFINAE_RETURNS
  331. (Op()(BOOST_HOF_FORWARD(T)(val), BOOST_HOF_FORWARD(X)(x)));
  332. };
  333. template<class Op>
  334. struct right
  335. {
  336. struct right_failure
  337. {
  338. template<class Failure>
  339. struct apply
  340. {
  341. template<class T, class U, class... Ts>
  342. struct of
  343. : Failure::template of<U, T, Ts...>
  344. {};
  345. };
  346. };
  347. struct failure
  348. : failure_map<right_failure, Op>
  349. {};
  350. template<class T, class X>
  351. constexpr BOOST_HOF_SFINAE_RESULT(const Op&, id_<X>, id_<T>)
  352. operator()(T&& val, X&& x) const BOOST_HOF_SFINAE_RETURNS
  353. (Op()(BOOST_HOF_FORWARD(X)(x), BOOST_HOF_FORWARD(T)(val)));
  354. };
  355. #define BOOST_HOF_UNAMED_PLACEHOLDER_UNARY_OP(op, name) \
  356. constexpr auto operator op () const BOOST_HOF_RETURNS \
  357. ( operators::name() );
  358. BOOST_HOF_FOREACH_UNARY_OP(BOOST_HOF_UNAMED_PLACEHOLDER_UNARY_OP)
  359. #define BOOST_HOF_UNAMED_PLACEHOLDER_ASSIGN_OP(op, name) \
  360. template<class T> \
  361. constexpr auto operator op (const T& x) const BOOST_HOF_RETURNS \
  362. ( partial_ap<T, left<operators::name>>(x) );
  363. BOOST_HOF_FOREACH_ASSIGN_OP(BOOST_HOF_UNAMED_PLACEHOLDER_ASSIGN_OP)
  364. };
  365. #define BOOST_HOF_UNAMED_PLACEHOLDER_BINARY_OP(op, name) \
  366. template<class T> \
  367. constexpr inline auto operator op (const unamed_placeholder&, const T& x) BOOST_HOF_RETURNS \
  368. ( unamed_placeholder::make_partial_ap<unamed_placeholder::right<operators::name>>(boost::hof::decay(x)) ); \
  369. template<class T> \
  370. constexpr inline auto operator op (const T& x, const unamed_placeholder&) BOOST_HOF_RETURNS \
  371. ( unamed_placeholder::make_partial_ap<unamed_placeholder::left<operators::name>>(boost::hof::decay(x)) ); \
  372. constexpr inline auto operator op (const unamed_placeholder&, const unamed_placeholder&) BOOST_HOF_RETURNS \
  373. ( operators::name() );
  374. BOOST_HOF_FOREACH_BINARY_OP(BOOST_HOF_UNAMED_PLACEHOLDER_BINARY_OP)
  375. }
  376. namespace placeholders {
  377. BOOST_HOF_DECLARE_STATIC_VAR(_, detail::unamed_placeholder);
  378. }
  379. using placeholders::_;
  380. }} // namespace boost::hof
  381. namespace std {
  382. template<int N>
  383. struct is_placeholder<boost::hof::placeholder<N>>
  384. : std::integral_constant<int, N>
  385. {};
  386. }
  387. namespace boost {
  388. template<class T>
  389. struct is_placeholder;
  390. template<int N>
  391. struct is_placeholder<boost::hof::placeholder<N>>
  392. : std::integral_constant<int, N>
  393. {};
  394. }
  395. #endif