1 // Copyright (C) 2016-2018 T. Zachary Laine 2 // 3 // Distributed under the Boost Software License, Version 1.0. (See 4 // accompanying file LICENSE_1_0.txt or copy at 5 // http://www.boost.org/LICENSE_1_0.txt) 6 #ifndef BOOST_YAP_ALGORITHM_HPP_INCLUDED 7 #define BOOST_YAP_ALGORITHM_HPP_INCLUDED 8 9 #include <boost/yap/algorithm_fwd.hpp> 10 #include <boost/yap/user_macros.hpp> 11 #include <boost/yap/detail/algorithm.hpp> 12 13 #include <boost/hana/size.hpp> 14 #include <boost/hana/comparing.hpp> 15 16 17 namespace boost { namespace yap { 18 19 #ifdef BOOST_NO_CONSTEXPR_IF 20 21 namespace detail { 22 23 template<typename Expr, bool MutableRvalueRef> 24 struct deref_impl 25 { operator ()boost::yap::detail::deref_impl26 constexpr decltype(auto) operator()(Expr && expr) 27 { 28 return std::move(*expr.elements[hana::llong_c<0>]); 29 } 30 }; 31 32 template<typename Expr> 33 struct deref_impl<Expr, false> 34 { operator ()boost::yap::detail::deref_impl35 constexpr decltype(auto) operator()(Expr && expr) 36 { 37 return *expr.elements[hana::llong_c<0>]; 38 } 39 }; 40 } 41 42 #endif 43 44 /** "Dereferences" a reference-expression, forwarding its referent to 45 the caller. */ 46 template<typename Expr> deref(Expr && expr)47 constexpr decltype(auto) deref(Expr && expr) 48 { 49 static_assert( 50 is_expr<Expr>::value, "deref() is only defined for expressions."); 51 52 static_assert( 53 detail::remove_cv_ref_t<Expr>::kind == expr_kind::expr_ref, 54 "deref() is only defined for expr_ref-kind expressions."); 55 56 #ifdef BOOST_NO_CONSTEXPR_IF 57 return detail::deref_impl < Expr, 58 std::is_rvalue_reference<Expr>::value && 59 !std::is_const<std::remove_reference_t<Expr>>::value > 60 {}(static_cast<Expr &&>(expr)); 61 #else 62 using namespace hana::literals; 63 if constexpr ( 64 std::is_rvalue_reference<Expr>::value && 65 !std::is_const<std::remove_reference_t<Expr>>::value) { 66 return std::move(*expr.elements[0_c]); 67 } else { 68 return *expr.elements[0_c]; 69 } 70 #endif 71 } 72 73 namespace detail { 74 75 template<typename Tuple, long long I> 76 struct lvalue_ref_ith_element 77 : std::is_lvalue_reference<decltype( 78 std::declval<Tuple>()[hana::llong<I>{}])> 79 { 80 }; 81 82 #ifdef BOOST_NO_CONSTEXPR_IF 83 84 template<bool ValueOfTerminalsOnly, typename T> 85 constexpr decltype(auto) value_impl(T && x); 86 87 template< 88 typename T, 89 bool IsExprRef, 90 bool ValueOfTerminalsOnly, 91 bool TakeValue, 92 bool IsLvalueRef> 93 struct value_expr_impl; 94 95 template< 96 typename T, 97 bool ValueOfTerminalsOnly, 98 bool TakeValue, 99 bool IsLvalueRef> 100 struct value_expr_impl< 101 T, 102 true, 103 ValueOfTerminalsOnly, 104 TakeValue, 105 IsLvalueRef> 106 { operator ()boost::yap::detail::value_expr_impl107 constexpr decltype(auto) operator()(T && x) 108 { 109 return ::boost::yap::detail::value_impl<ValueOfTerminalsOnly>( 110 ::boost::yap::deref(static_cast<T &&>(x))); 111 } 112 }; 113 114 template<typename T, bool ValueOfTerminalsOnly> 115 struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, true> 116 { operator ()boost::yap::detail::value_expr_impl117 constexpr decltype(auto) operator()(T && x) 118 { 119 return x.elements[hana::llong_c<0>]; 120 } 121 }; 122 123 template<typename T, bool ValueOfTerminalsOnly> 124 struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, false> 125 { operator ()boost::yap::detail::value_expr_impl126 constexpr decltype(auto) operator()(T && x) 127 { 128 return std::move(x.elements[hana::llong_c<0>]); 129 } 130 }; 131 132 template<typename T, bool ValueOfTerminalsOnly, bool IsLvalueRef> 133 struct value_expr_impl< 134 T, 135 false, 136 ValueOfTerminalsOnly, 137 false, 138 IsLvalueRef> 139 { operator ()boost::yap::detail::value_expr_impl140 constexpr decltype(auto) operator()(T && x) 141 { 142 return static_cast<T &&>(x); 143 } 144 }; 145 146 template<typename T, bool IsExpr, bool ValueOfTerminalsOnly> 147 struct value_impl_t 148 { operator ()boost::yap::detail::value_impl_t149 constexpr decltype(auto) operator()(T && x) 150 { 151 constexpr expr_kind kind = detail::remove_cv_ref_t<T>::kind; 152 constexpr detail::expr_arity arity = detail::arity_of<kind>(); 153 return value_expr_impl < T, kind == expr_kind::expr_ref, 154 ValueOfTerminalsOnly, 155 (ValueOfTerminalsOnly && kind == expr_kind::terminal) || 156 (!ValueOfTerminalsOnly && 157 arity == detail::expr_arity::one), 158 std::is_lvalue_reference<T>::value || 159 detail::lvalue_ref_ith_element< 160 decltype(x.elements), 161 0>::value > {}(static_cast<T &&>(x)); 162 } 163 }; 164 165 template<typename T, bool ValueOfTerminalsOnly> 166 struct value_impl_t<T, false, ValueOfTerminalsOnly> 167 { operator ()boost::yap::detail::value_impl_t168 constexpr decltype(auto) operator()(T && x) 169 { 170 return static_cast<T &&>(x); 171 } 172 }; 173 174 template<bool ValueOfTerminalsOnly, typename T> value_impl(T && x)175 constexpr decltype(auto) value_impl(T && x) 176 { 177 return detail:: 178 value_impl_t<T, is_expr<T>::value, ValueOfTerminalsOnly>{}( 179 static_cast<T &&>(x)); 180 } 181 182 #else 183 184 template<bool ValueOfTerminalsOnly, typename T> value_impl(T && x)185 constexpr decltype(auto) value_impl(T && x) 186 { 187 if constexpr (is_expr<T>::value) { 188 using namespace hana::literals; 189 constexpr expr_kind kind = remove_cv_ref_t<T>::kind; 190 constexpr expr_arity arity = arity_of<kind>(); 191 if constexpr (kind == expr_kind::expr_ref) { 192 return value_impl<ValueOfTerminalsOnly>( 193 ::boost::yap::deref(static_cast<T &&>(x))); 194 } else if constexpr ( 195 kind == expr_kind::terminal || 196 (!ValueOfTerminalsOnly && arity == expr_arity::one)) { 197 if constexpr ( 198 std::is_lvalue_reference<T>::value || 199 detail:: 200 lvalue_ref_ith_element<decltype(x.elements), 0>{}) { 201 return x.elements[0_c]; 202 } else { 203 return std::move(x.elements[0_c]); 204 } 205 } else { 206 return static_cast<T &&>(x); 207 } 208 } else { 209 return static_cast<T &&>(x); 210 } 211 } 212 213 #endif 214 } 215 216 /** Forwards the sole element of \a x to the caller, possibly calling 217 <code>deref()</code> first if \a x is a reference expression, or 218 forwards \a x to the caller unchanged. 219 220 More formally: 221 222 - If \a x is not an expression, \a x is forwarded to the caller. 223 224 - Otherwise, if \a x is a reference expression, the result is 225 <code>value(deref(x))</code>. 226 227 - Otherwise, if \a x is an expression with only one value (a unary 228 expression or a terminal expression), the result is the forwarded 229 first element of \a x. 230 231 - Otherwise, \a x is forwarded to the caller. */ 232 template<typename T> value(T && x)233 constexpr decltype(auto) value(T && x) 234 { 235 return detail::value_impl<false>(static_cast<T &&>(x)); 236 } 237 238 #ifdef BOOST_NO_CONSTEXPR_IF 239 240 template<typename Expr, typename I> 241 constexpr decltype(auto) get(Expr && expr, I const & i); 242 243 namespace detail { 244 245 template<long long I, typename Expr, bool IsExpr, bool IsLvalueRef> 246 struct get_impl; 247 248 template<long long I, typename Expr, bool IsLvalueRef> 249 struct get_impl<I, Expr, true, IsLvalueRef> 250 { operator ()boost::yap::detail::get_impl251 constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i) 252 { 253 return ::boost::yap::get( 254 ::boost::yap::deref(static_cast<Expr &&>(expr)), i); 255 } 256 }; 257 258 template<long long I, typename Expr> 259 struct get_impl<I, Expr, false, true> 260 { operator ()boost::yap::detail::get_impl261 constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i) 262 { 263 return expr.elements[i]; 264 } 265 }; 266 267 template<long long I, typename Expr> 268 struct get_impl<I, Expr, false, false> 269 { operator ()boost::yap::detail::get_impl270 constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i) 271 { 272 return std::move(expr.elements[i]); 273 } 274 }; 275 } 276 277 #endif 278 279 /** Forwards the <i>i</i>-th element of \a expr to the caller. If \a 280 expr is a reference expression, the result is <code>get(deref(expr), 281 i)</code>. 282 283 \note <code>get()</code> is only valid if \a Expr is an expression. 284 */ 285 template<typename Expr, typename I> get(Expr && expr,I const & i)286 constexpr decltype(auto) get(Expr && expr, I const & i) 287 { 288 static_assert( 289 is_expr<Expr>::value, "get() is only defined for expressions."); 290 static_assert( 291 hana::IntegralConstant<I>::value, 292 "'i' must be an IntegralConstant"); 293 294 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 295 296 static_assert( 297 kind == expr_kind::expr_ref || 298 (0 <= I::value && 299 I::value < decltype(hana::size(expr.elements))::value), 300 "In get(expr, I), I must be a valid index into expr's tuple " 301 "elements."); 302 303 #ifdef BOOST_NO_CONSTEXPR_IF 304 return detail::get_impl< 305 I::value, 306 Expr, 307 kind == expr_kind::expr_ref, 308 std::is_lvalue_reference<Expr>::value>{}(static_cast<Expr &&>(expr), i); 309 #else 310 using namespace hana::literals; 311 if constexpr (kind == expr_kind::expr_ref) { 312 return ::boost::yap::get( 313 ::boost::yap::deref(static_cast<Expr &&>(expr)), i); 314 } else { 315 if constexpr (std::is_lvalue_reference<Expr>::value) { 316 return expr.elements[i]; 317 } else { 318 return std::move(expr.elements[i]); 319 } 320 } 321 #endif 322 } 323 324 /** Returns <code>get(expr, boost::hana::llong_c<I>)</code>. */ 325 template<long long I, typename Expr> get_c(Expr && expr)326 constexpr decltype(auto) get_c(Expr && expr) 327 { 328 return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<I>); 329 } 330 331 /** Returns the left operand in a binary operator expression. 332 333 Equivalent to <code>get(expr, 0_c)</code>. 334 335 \note <code>left()</code> is only valid if \a Expr is a binary 336 operator expression. 337 */ 338 template<typename Expr> left(Expr && expr)339 constexpr decltype(auto) left(Expr && expr) 340 { 341 using namespace hana::literals; 342 return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c); 343 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 344 static_assert( 345 kind == expr_kind::expr_ref || 346 detail::arity_of<kind>() == detail::expr_arity::two, 347 "left() is only defined for binary expressions."); 348 } 349 350 /** Returns the right operand in a binary operator expression. 351 352 Equivalent to <code>get(expr, 1_c)</code>. 353 354 \note <code>right()</code> is only valid if \a Expr is a binary 355 operator expression. 356 */ 357 template<typename Expr> right(Expr && expr)358 constexpr decltype(auto) right(Expr && expr) 359 { 360 using namespace hana::literals; 361 return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c); 362 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 363 static_assert( 364 kind == expr_kind::expr_ref || 365 detail::arity_of<kind>() == detail::expr_arity::two, 366 "right() is only defined for binary expressions."); 367 } 368 369 /** Returns the condition expression in an if_else expression. 370 371 Equivalent to <code>get(expr, 0_c)</code>. 372 373 \note <code>cond()</code> is only valid if \a Expr is an 374 <code>expr_kind::if_else</code> expression. 375 */ 376 template<typename Expr> cond(Expr && expr)377 constexpr decltype(auto) cond(Expr && expr) 378 { 379 using namespace hana::literals; 380 return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c); 381 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 382 static_assert( 383 kind == expr_kind::expr_ref || kind == expr_kind::if_else, 384 "cond() is only defined for if_else expressions."); 385 } 386 387 /** Returns the then-expression in an if_else expression. 388 389 Equivalent to <code>get(expr, 1_c)</code>. 390 391 \note <code>then()</code> is only valid if \a Expr is an 392 <code>expr_kind::if_else</code> expression. 393 */ 394 template<typename Expr> then(Expr && expr)395 constexpr decltype(auto) then(Expr && expr) 396 { 397 using namespace hana::literals; 398 return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c); 399 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 400 static_assert( 401 kind == expr_kind::expr_ref || kind == expr_kind::if_else, 402 "then() is only defined for if_else expressions."); 403 } 404 405 /** Returns the else-expression in an if_else expression. 406 407 Equivalent to <code>get(expr, 2_c)</code>. 408 409 \note <code>else_()</code> is only valid if \a Expr is an 410 <code>expr_kind::if_else</code> expression. 411 */ 412 template<typename Expr> else_(Expr && expr)413 constexpr decltype(auto) else_(Expr && expr) 414 { 415 using namespace hana::literals; 416 return ::boost::yap::get(static_cast<Expr &&>(expr), 2_c); 417 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 418 static_assert( 419 kind == expr_kind::expr_ref || kind == expr_kind::if_else, 420 "else_() is only defined for if_else expressions."); 421 } 422 423 /** Returns the callable in a call expression. 424 425 Equivalent to <code>get(expr, 0)</code>. 426 427 \note <code>callable()</code> is only valid if \a Expr is an 428 <code>expr_kind::call</code> expression. 429 */ 430 template<typename Expr> callable(Expr && expr)431 constexpr decltype(auto) callable(Expr && expr) 432 { 433 return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<0>); 434 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 435 static_assert( 436 kind == expr_kind::expr_ref || 437 detail::arity_of<kind>() == detail::expr_arity::n, 438 "callable() is only defined for call expressions."); 439 } 440 441 /** Returns the <i>i-th</i> argument expression in a call expression. 442 443 Equivalent to <code>get(expr, i + 1)</code>. 444 445 \note <code>argument()</code> is only valid if \a Expr is an 446 <code>expr_kind::call</code> expression. 447 */ 448 template<long long I, typename Expr> argument(Expr && expr,hana::llong<I> i)449 constexpr decltype(auto) argument(Expr && expr, hana::llong<I> i) 450 { 451 return ::boost::yap::get( 452 static_cast<Expr &&>(expr), hana::llong_c<I + 1>); 453 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 454 static_assert( 455 kind == expr_kind::expr_ref || 456 detail::arity_of<kind>() == detail::expr_arity::n, 457 "argument() is only defined for call expressions."); 458 static_assert( 459 kind == expr_kind::expr_ref || 460 (0 <= I && I < decltype(hana::size(expr.elements))::value - 1), 461 "I must be a valid call-expression argument index."); 462 } 463 464 /** Makes a new expression instantiated from the expression template \a 465 ExprTemplate, of kind \a Kind, with the given values as its 466 elements. 467 468 For each parameter P: 469 470 - If P is an expression, P is moved into the result if P is an 471 rvalue and captured by reference into the result otherwise. 472 473 - Otherwise, P is wrapped in a terminal expression. 474 475 \note <code>make_expression()</code> is only valid if the number of 476 parameters passed is appropriate for \a Kind. 477 */ 478 template< 479 template<expr_kind, class> class ExprTemplate, 480 expr_kind Kind, 481 typename... T> make_expression(T &&...t)482 constexpr auto make_expression(T &&... t) 483 { 484 constexpr detail::expr_arity arity = detail::arity_of<Kind>(); 485 static_assert( 486 (arity == detail::expr_arity::one && sizeof...(T) == 1) || 487 (arity == detail::expr_arity::two && sizeof...(T) == 2) || 488 (arity == detail::expr_arity::three && sizeof...(T) == 3) || 489 arity == detail::expr_arity::n, 490 "The number of parameters passed to make_expression() must " 491 "match the arity " 492 "implied by the expr_kind template parameter."); 493 using tuple_type = 494 hana::tuple<detail::operand_type_t<ExprTemplate, T>...>; 495 return ExprTemplate<Kind, tuple_type>{tuple_type{ 496 detail::make_operand<detail::operand_type_t<ExprTemplate, T>>{}( 497 static_cast<T &&>(t))...}}; 498 } 499 500 /** Makes a new terminal expression instantiated from the expression 501 template \a ExprTemplate, with the given value as its sole element. 502 503 \note <code>make_terminal()</code> is only valid if \a T is \b not 504 an expression. 505 */ 506 template<template<expr_kind, class> class ExprTemplate, typename T> make_terminal(T && t)507 constexpr auto make_terminal(T && t) 508 { 509 static_assert( 510 !is_expr<T>::value, 511 "make_terminal() is only defined for non expressions."); 512 using result_type = detail::operand_type_t<ExprTemplate, T>; 513 using tuple_type = decltype(std::declval<result_type>().elements); 514 return result_type{tuple_type{static_cast<T &&>(t)}}; 515 } 516 517 #ifdef BOOST_NO_CONSTEXPR_IF 518 519 namespace detail { 520 521 template< 522 template<expr_kind, class> class ExprTemplate, 523 typename T, 524 bool IsExpr> 525 struct as_expr_impl 526 { operator ()boost::yap::detail::as_expr_impl527 constexpr decltype(auto) operator()(T && t) 528 { 529 return static_cast<T &&>(t); 530 } 531 }; 532 533 template<template<expr_kind, class> class ExprTemplate, typename T> 534 struct as_expr_impl<ExprTemplate, T, false> 535 { operator ()boost::yap::detail::as_expr_impl536 constexpr decltype(auto) operator()(T && t) 537 { 538 return make_terminal<ExprTemplate>(static_cast<T &&>(t)); 539 } 540 }; 541 } 542 543 #endif 544 545 /** Returns an expression formed from \a t as follows: 546 547 - If \a t is an expression, \a t is forwarded to the caller. 548 549 - Otherwise, \a t is wrapped in a terminal expression. 550 */ 551 template<template<expr_kind, class> class ExprTemplate, typename T> as_expr(T && t)552 constexpr decltype(auto) as_expr(T && t) 553 { 554 #ifdef BOOST_NO_CONSTEXPR_IF 555 return detail::as_expr_impl<ExprTemplate, T, is_expr<T>::value>{}( 556 static_cast<T &&>(t)); 557 #else 558 if constexpr (is_expr<T>::value) { 559 return static_cast<T &&>(t); 560 } else { 561 return make_terminal<ExprTemplate>(static_cast<T &&>(t)); 562 } 563 #endif 564 } 565 566 /** A callable type that evaluates its contained expression when called. 567 568 \see <code>make_expression_function()</code> 569 */ 570 template<typename Expr> 571 struct expression_function 572 { 573 template<typename... U> operator ()boost::yap::expression_function574 constexpr decltype(auto) operator()(U &&... u) 575 { 576 return ::boost::yap::evaluate(expr, static_cast<U &&>(u)...); 577 } 578 579 Expr expr; 580 }; 581 582 namespace detail { 583 584 template<expr_kind Kind, typename Tuple> 585 struct expression_function_expr 586 { 587 static const expr_kind kind = Kind; 588 Tuple elements; 589 }; 590 } 591 592 /** Returns a callable object that \a expr has been forwarded into. This 593 is useful for using expressions as function objects. 594 595 Lvalue expressions are stored in the result by reference; rvalue 596 expressions are moved into the result. 597 598 \note <code>make_expression_function()</code> is only valid if \a 599 Expr is an expression. 600 */ 601 template<typename Expr> make_expression_function(Expr && expr)602 constexpr auto make_expression_function(Expr && expr) 603 { 604 static_assert( 605 is_expr<Expr>::value, 606 "make_expression_function() is only defined for expressions."); 607 using stored_type = 608 detail::operand_type_t<detail::expression_function_expr, Expr &&>; 609 return expression_function<stored_type>{ 610 detail::make_operand<stored_type>{}(static_cast<Expr &&>(expr))}; 611 } 612 }} 613 614 #include <boost/yap/detail/transform.hpp> 615 616 namespace boost { namespace yap { 617 618 /** Returns a transform object that replaces placeholders within an 619 expression with the given values. 620 */ 621 template<typename... T> replacements(T &&...t)622 constexpr auto replacements(T &&... t) 623 { 624 return detail::placeholder_transform_t<T...>(static_cast<T &&>(t)...); 625 } 626 627 /** Returns \a expr with the placeholders replaced by YAP terminals 628 containing the given values. 629 630 \note <code>replace_placeholders(expr, t...)</code> is only valid if 631 \a expr is an expression, and <code>max_p <= sizeof...(t)</code>, 632 where <code>max_p</code> is the maximum placeholder index in \a expr. 633 */ 634 template<typename Expr, typename... T> replace_placeholders(Expr && expr,T &&...t)635 constexpr decltype(auto) replace_placeholders(Expr && expr, T &&... t) 636 { 637 static_assert( 638 is_expr<Expr>::value, 639 "evaluate() is only defined for expressions."); 640 return transform( 641 static_cast<Expr &&>(expr), replacements(static_cast<T &&>(t)...)); 642 } 643 644 /** Returns a transform object that evaluates an expression using the 645 built-in semantics. The transform replaces any placeholders with the 646 given values. 647 */ 648 template<typename... T> evaluation(T &&...t)649 constexpr auto evaluation(T &&... t) 650 { 651 return detail::evaluation_transform_t<T...>(static_cast<T &&>(t)...); 652 } 653 654 /** Evaluates \a expr using the built-in semantics, replacing any 655 placeholders with the given values. 656 657 \note <code>evaluate(expr)</code> is only valid if \a expr is an 658 expression. 659 */ 660 template<typename Expr, typename... T> evaluate(Expr && expr,T &&...t)661 constexpr decltype(auto) evaluate(Expr && expr, T &&... t) 662 { 663 static_assert( 664 is_expr<Expr>::value, 665 "evaluate() is only defined for expressions."); 666 return transform( 667 static_cast<Expr &&>(expr), evaluation(static_cast<T &&>(t)...)); 668 } 669 670 namespace detail { 671 672 template<typename... Transforms> make_transform_tuple(Transforms &...transforms)673 constexpr auto make_transform_tuple(Transforms &... transforms) 674 { 675 return hana::tuple<Transforms *...>{&transforms...}; 676 } 677 678 template<bool Strict> 679 struct transform_ 680 { 681 template<typename Expr, typename Transform, typename... Transforms> operator ()boost::yap::detail::transform_682 constexpr decltype(auto) operator()( 683 Expr && expr, Transform & transform, Transforms &... transforms) const 684 { 685 auto transform_tuple = 686 detail::make_transform_tuple(transform, transforms...); 687 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind; 688 return detail:: 689 transform_impl<Strict, 0, kind == expr_kind::expr_ref>{}( 690 static_cast<Expr &&>(expr), transform_tuple); 691 } 692 }; 693 } 694 695 /** Returns the result of transforming (all or part of) \a expr using 696 whatever overloads of <code>Transform::operator()</code> match \a 697 expr. 698 699 \note Transformations can do anything: they may have side effects; 700 they may mutate values; they may mutate types; and they may do any 701 combination of these. 702 */ 703 template<typename Expr, typename Transform, typename... Transforms> 704 constexpr decltype(auto) transform(Expr && expr,Transform && transform,Transforms &&...transforms)705 transform(Expr && expr, Transform && transform, Transforms &&... transforms) 706 { 707 static_assert( 708 is_expr<Expr>::value, 709 "transform() is only defined for expressions."); 710 return detail::transform_<false>{}( 711 static_cast<Expr &&>(expr), transform, transforms...); 712 } 713 714 /** Returns the result of transforming \a expr using whichever overload of 715 <code>Transform::operator()</code> best matches \a expr. If no 716 overload of <code>Transform::operator()</code> matches, a compile-time 717 error results. 718 719 \note Transformations can do anything: they may have side effects; 720 they may mutate values; they may mutate types; and they may do any 721 combination of these. 722 */ 723 template<typename Expr, typename Transform, typename... Transforms> transform_strict(Expr && expr,Transform && transform,Transforms &&...transforms)724 constexpr decltype(auto) transform_strict( 725 Expr && expr, Transform && transform, Transforms &&... transforms) 726 { 727 static_assert( 728 is_expr<Expr>::value, 729 "transform() is only defined for expressions."); 730 return detail::transform_<true>{}( 731 static_cast<Expr &&>(expr), transform, transforms...); 732 } 733 734 }} 735 736 #endif 737