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