Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:53:56

0001 // Copyright (C) 2016-2018 T. Zachary Laine
0002 //
0003 // Distributed under the Boost Software License, Version 1.0. (See
0004 // accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 #ifndef BOOST_YAP_ALGORITHM_HPP_INCLUDED
0007 #define BOOST_YAP_ALGORITHM_HPP_INCLUDED
0008 
0009 #include <boost/yap/algorithm_fwd.hpp>
0010 #include <boost/yap/user_macros.hpp>
0011 #include <boost/yap/detail/algorithm.hpp>
0012 
0013 #include <boost/hana/size.hpp>
0014 #include <boost/hana/comparing.hpp>
0015 
0016 
0017 namespace boost { namespace yap {
0018 
0019 #ifdef BOOST_NO_CONSTEXPR_IF
0020 
0021     namespace detail {
0022 
0023         template<typename Expr, bool MutableRvalueRef>
0024         struct deref_impl
0025         {
0026             constexpr decltype(auto) operator()(Expr && expr)
0027             {
0028                 return std::move(*expr.elements[hana::llong_c<0>]);
0029             }
0030         };
0031 
0032         template<typename Expr>
0033         struct deref_impl<Expr, false>
0034         {
0035             constexpr decltype(auto) operator()(Expr && expr)
0036             {
0037                 return *expr.elements[hana::llong_c<0>];
0038             }
0039         };
0040     }
0041 
0042 #endif
0043 
0044     /** "Dereferences" a reference-expression, forwarding its referent to
0045        the caller. */
0046     template<typename Expr>
0047     constexpr decltype(auto) deref(Expr && expr)
0048     {
0049         static_assert(
0050             is_expr<Expr>::value, "deref() is only defined for expressions.");
0051 
0052         static_assert(
0053             detail::remove_cv_ref_t<Expr>::kind == expr_kind::expr_ref,
0054             "deref() is only defined for expr_ref-kind expressions.");
0055 
0056 #ifdef BOOST_NO_CONSTEXPR_IF
0057         return detail::deref_impl < Expr,
0058                std::is_rvalue_reference<Expr>::value &&
0059                    !std::is_const<std::remove_reference_t<Expr>>::value >
0060                        {}(static_cast<Expr &&>(expr));
0061 #else
0062         using namespace hana::literals;
0063         if constexpr (
0064             std::is_rvalue_reference<Expr>::value &&
0065             !std::is_const<std::remove_reference_t<Expr>>::value) {
0066             return std::move(*expr.elements[0_c]);
0067         } else {
0068             return *expr.elements[0_c];
0069         }
0070 #endif
0071     }
0072 
0073     namespace detail {
0074 
0075         template<typename Tuple, long long I>
0076         struct lvalue_ref_ith_element
0077             : std::is_lvalue_reference<decltype(
0078                   std::declval<Tuple>()[hana::llong<I>{}])>
0079         {
0080         };
0081 
0082 #ifdef BOOST_NO_CONSTEXPR_IF
0083 
0084         template<bool ValueOfTerminalsOnly, typename T>
0085         constexpr decltype(auto) value_impl(T && x);
0086 
0087         template<
0088             typename T,
0089             bool IsExprRef,
0090             bool ValueOfTerminalsOnly,
0091             bool TakeValue,
0092             bool IsLvalueRef>
0093         struct value_expr_impl;
0094 
0095         template<
0096             typename T,
0097             bool ValueOfTerminalsOnly,
0098             bool TakeValue,
0099             bool IsLvalueRef>
0100         struct value_expr_impl<
0101             T,
0102             true,
0103             ValueOfTerminalsOnly,
0104             TakeValue,
0105             IsLvalueRef>
0106         {
0107             constexpr decltype(auto) operator()(T && x)
0108             {
0109                 return ::boost::yap::detail::value_impl<ValueOfTerminalsOnly>(
0110                     ::boost::yap::deref(static_cast<T &&>(x)));
0111             }
0112         };
0113 
0114         template<typename T, bool ValueOfTerminalsOnly>
0115         struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, true>
0116         {
0117             constexpr decltype(auto) operator()(T && x)
0118             {
0119                 return x.elements[hana::llong_c<0>];
0120             }
0121         };
0122 
0123         template<typename T, bool ValueOfTerminalsOnly>
0124         struct value_expr_impl<T, false, ValueOfTerminalsOnly, true, false>
0125         {
0126             constexpr decltype(auto) operator()(T && x)
0127             {
0128                 return std::move(x.elements[hana::llong_c<0>]);
0129             }
0130         };
0131 
0132         template<typename T, bool ValueOfTerminalsOnly, bool IsLvalueRef>
0133         struct value_expr_impl<
0134             T,
0135             false,
0136             ValueOfTerminalsOnly,
0137             false,
0138             IsLvalueRef>
0139         {
0140             constexpr decltype(auto) operator()(T && x)
0141             {
0142                 return static_cast<T &&>(x);
0143             }
0144         };
0145 
0146         template<typename T, bool IsExpr, bool ValueOfTerminalsOnly>
0147         struct value_impl_t
0148         {
0149             constexpr decltype(auto) operator()(T && x)
0150             {
0151                 constexpr expr_kind kind = detail::remove_cv_ref_t<T>::kind;
0152                 constexpr detail::expr_arity arity = detail::arity_of<kind>();
0153                 return value_expr_impl < T, kind == expr_kind::expr_ref,
0154                        ValueOfTerminalsOnly,
0155                        (ValueOfTerminalsOnly && kind == expr_kind::terminal) ||
0156                            (!ValueOfTerminalsOnly &&
0157                             arity == detail::expr_arity::one),
0158                        std::is_lvalue_reference<T>::value ||
0159                            detail::lvalue_ref_ith_element<
0160                                decltype(x.elements),
0161                                0>::value > {}(static_cast<T &&>(x));
0162             }
0163         };
0164 
0165         template<typename T, bool ValueOfTerminalsOnly>
0166         struct value_impl_t<T, false, ValueOfTerminalsOnly>
0167         {
0168             constexpr decltype(auto) operator()(T && x)
0169             {
0170                 return static_cast<T &&>(x);
0171             }
0172         };
0173 
0174         template<bool ValueOfTerminalsOnly, typename T>
0175         constexpr decltype(auto) value_impl(T && x)
0176         {
0177             return detail::
0178                 value_impl_t<T, is_expr<T>::value, ValueOfTerminalsOnly>{}(
0179                     static_cast<T &&>(x));
0180         }
0181 
0182 #else
0183 
0184         template<bool ValueOfTerminalsOnly, typename T>
0185         constexpr decltype(auto) value_impl(T && x)
0186         {
0187             if constexpr (is_expr<T>::value) {
0188                 using namespace hana::literals;
0189                 constexpr expr_kind kind = remove_cv_ref_t<T>::kind;
0190                 constexpr expr_arity arity = arity_of<kind>();
0191                 if constexpr (kind == expr_kind::expr_ref) {
0192                     return value_impl<ValueOfTerminalsOnly>(
0193                         ::boost::yap::deref(static_cast<T &&>(x)));
0194                 } else if constexpr (
0195                     kind == expr_kind::terminal ||
0196                     (!ValueOfTerminalsOnly && arity == expr_arity::one)) {
0197                     if constexpr (
0198                         std::is_lvalue_reference<T>::value ||
0199                         detail::
0200                             lvalue_ref_ith_element<decltype(x.elements), 0>{}) {
0201                         return x.elements[0_c];
0202                     } else {
0203                         return std::move(x.elements[0_c]);
0204                     }
0205                 } else {
0206                     return static_cast<T &&>(x);
0207                 }
0208             } else {
0209                 return static_cast<T &&>(x);
0210             }
0211         }
0212 
0213 #endif
0214     }
0215 
0216     /** Forwards the sole element of \a x to the caller, possibly calling
0217         <code>deref()</code> first if \a x is a reference expression, or
0218         forwards \a x to the caller unchanged.
0219 
0220         More formally:
0221 
0222         - If \a x is not an expression, \a x is forwarded to the caller.
0223 
0224         - Otherwise, if \a x is a reference expression, the result is
0225         <code>value(deref(x))</code>.
0226 
0227         - Otherwise, if \a x is an expression with only one value (a unary
0228         expression or a terminal expression), the result is the forwarded
0229         first element of \a x.
0230 
0231         - Otherwise, \a x is forwarded to the caller. */
0232     template<typename T>
0233     constexpr decltype(auto) value(T && x)
0234     {
0235         return detail::value_impl<false>(static_cast<T &&>(x));
0236     }
0237 
0238 #ifdef BOOST_NO_CONSTEXPR_IF
0239 
0240     template<typename Expr, typename I>
0241     constexpr decltype(auto) get(Expr && expr, I const & i);
0242 
0243     namespace detail {
0244 
0245         template<long long I, typename Expr, bool IsExpr, bool IsLvalueRef>
0246         struct get_impl;
0247 
0248         template<long long I, typename Expr, bool IsLvalueRef>
0249         struct get_impl<I, Expr, true, IsLvalueRef>
0250         {
0251             constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
0252             {
0253                 return ::boost::yap::get(
0254                     ::boost::yap::deref(static_cast<Expr &&>(expr)), i);
0255             }
0256         };
0257 
0258         template<long long I, typename Expr>
0259         struct get_impl<I, Expr, false, true>
0260         {
0261             constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
0262             {
0263                 return expr.elements[i];
0264             }
0265         };
0266 
0267         template<long long I, typename Expr>
0268         struct get_impl<I, Expr, false, false>
0269         {
0270             constexpr decltype(auto) operator()(Expr && expr, hana::llong<I> i)
0271             {
0272                 return std::move(expr.elements[i]);
0273             }
0274         };
0275     }
0276 
0277 #endif
0278 
0279     /** Forwards the <i>i</i>-th element of \a expr to the caller.  If \a
0280        expr is a reference expression, the result is <code>get(deref(expr),
0281         i)</code>.
0282 
0283         \note <code>get()</code> is only valid if \a Expr is an expression.
0284     */
0285     template<typename Expr, typename I>
0286     constexpr decltype(auto) get(Expr && expr, I const & i)
0287     {
0288         static_assert(
0289             is_expr<Expr>::value, "get() is only defined for expressions.");
0290         static_assert(
0291             hana::IntegralConstant<I>::value,
0292             "'i' must be an IntegralConstant");
0293 
0294         constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0295 
0296         static_assert(
0297             kind == expr_kind::expr_ref ||
0298                 (0 <= I::value &&
0299                  I::value < decltype(hana::size(expr.elements))::value),
0300             "In get(expr, I), I must be a valid index into expr's tuple "
0301             "elements.");
0302 
0303 #ifdef BOOST_NO_CONSTEXPR_IF
0304         return detail::get_impl<
0305             I::value,
0306             Expr,
0307             kind == expr_kind::expr_ref,
0308             std::is_lvalue_reference<Expr>::value>{}(static_cast<Expr &&>(expr), i);
0309 #else
0310         using namespace hana::literals;
0311         if constexpr (kind == expr_kind::expr_ref) {
0312             return ::boost::yap::get(
0313                 ::boost::yap::deref(static_cast<Expr &&>(expr)), i);
0314         } else {
0315             if constexpr (std::is_lvalue_reference<Expr>::value) {
0316                 return expr.elements[i];
0317             } else {
0318                 return std::move(expr.elements[i]);
0319             }
0320         }
0321 #endif
0322     }
0323 
0324     /** Returns <code>get(expr, boost::hana::llong_c<I>)</code>. */
0325     template<long long I, typename Expr>
0326     constexpr decltype(auto) get_c(Expr && expr)
0327     {
0328         return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<I>);
0329     }
0330 
0331     /** Returns the left operand in a binary operator expression.
0332 
0333         Equivalent to <code>get(expr, 0_c)</code>.
0334 
0335         \note <code>left()</code> is only valid if \a Expr is a binary
0336         operator expression.
0337     */
0338     template<typename Expr>
0339     constexpr decltype(auto) left(Expr && expr)
0340     {
0341         using namespace hana::literals;
0342         return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c);
0343         constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0344         static_assert(
0345             kind == expr_kind::expr_ref ||
0346                 detail::arity_of<kind>() == detail::expr_arity::two,
0347             "left() is only defined for binary expressions.");
0348     }
0349 
0350     /** Returns the right operand in a binary operator expression.
0351 
0352         Equivalent to <code>get(expr, 1_c)</code>.
0353 
0354         \note <code>right()</code> is only valid if \a Expr is a binary
0355         operator expression.
0356     */
0357     template<typename Expr>
0358     constexpr decltype(auto) right(Expr && expr)
0359     {
0360         using namespace hana::literals;
0361         return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c);
0362         constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0363         static_assert(
0364             kind == expr_kind::expr_ref ||
0365                 detail::arity_of<kind>() == detail::expr_arity::two,
0366             "right() is only defined for binary expressions.");
0367     }
0368 
0369     /** Returns the condition expression in an if_else expression.
0370 
0371         Equivalent to <code>get(expr, 0_c)</code>.
0372 
0373         \note <code>cond()</code> is only valid if \a Expr is an
0374         <code>expr_kind::if_else</code> expression.
0375     */
0376     template<typename Expr>
0377     constexpr decltype(auto) cond(Expr && expr)
0378     {
0379         using namespace hana::literals;
0380         return ::boost::yap::get(static_cast<Expr &&>(expr), 0_c);
0381         constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0382         static_assert(
0383             kind == expr_kind::expr_ref || kind == expr_kind::if_else,
0384             "cond() is only defined for if_else expressions.");
0385     }
0386 
0387     /** Returns the then-expression in an if_else expression.
0388 
0389         Equivalent to <code>get(expr, 1_c)</code>.
0390 
0391         \note <code>then()</code> is only valid if \a Expr is an
0392         <code>expr_kind::if_else</code> expression.
0393     */
0394     template<typename Expr>
0395     constexpr decltype(auto) then(Expr && expr)
0396     {
0397         using namespace hana::literals;
0398         return ::boost::yap::get(static_cast<Expr &&>(expr), 1_c);
0399         constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0400         static_assert(
0401             kind == expr_kind::expr_ref || kind == expr_kind::if_else,
0402             "then() is only defined for if_else expressions.");
0403     }
0404 
0405     /** Returns the else-expression in an if_else expression.
0406 
0407         Equivalent to <code>get(expr, 2_c)</code>.
0408 
0409         \note <code>else_()</code> is only valid if \a Expr is an
0410         <code>expr_kind::if_else</code> expression.
0411     */
0412     template<typename Expr>
0413     constexpr decltype(auto) else_(Expr && expr)
0414     {
0415         using namespace hana::literals;
0416         return ::boost::yap::get(static_cast<Expr &&>(expr), 2_c);
0417         constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0418         static_assert(
0419             kind == expr_kind::expr_ref || kind == expr_kind::if_else,
0420             "else_() is only defined for if_else expressions.");
0421     }
0422 
0423     /** Returns the callable in a call expression.
0424 
0425         Equivalent to <code>get(expr, 0)</code>.
0426 
0427         \note <code>callable()</code> is only valid if \a Expr is an
0428         <code>expr_kind::call</code> expression.
0429     */
0430     template<typename Expr>
0431     constexpr decltype(auto) callable(Expr && expr)
0432     {
0433         return ::boost::yap::get(static_cast<Expr &&>(expr), hana::llong_c<0>);
0434         constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0435         static_assert(
0436             kind == expr_kind::expr_ref ||
0437                 detail::arity_of<kind>() == detail::expr_arity::n,
0438             "callable() is only defined for call expressions.");
0439     }
0440 
0441     /** Returns the <i>i-th</i> argument expression in a call expression.
0442 
0443         Equivalent to <code>get(expr, i + 1)</code>.
0444 
0445         \note <code>argument()</code> is only valid if \a Expr is an
0446         <code>expr_kind::call</code> expression.
0447     */
0448     template<long long I, typename Expr>
0449     constexpr decltype(auto) argument(Expr && expr, hana::llong<I> i)
0450     {
0451         return ::boost::yap::get(
0452             static_cast<Expr &&>(expr), hana::llong_c<I + 1>);
0453         constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0454         static_assert(
0455             kind == expr_kind::expr_ref ||
0456                 detail::arity_of<kind>() == detail::expr_arity::n,
0457             "argument() is only defined for call expressions.");
0458         static_assert(
0459             kind == expr_kind::expr_ref ||
0460                 (0 <= I && I < decltype(hana::size(expr.elements))::value - 1),
0461             "I must be a valid call-expression argument index.");
0462     }
0463 
0464     /** Makes a new expression instantiated from the expression template \a
0465         ExprTemplate, of kind \a Kind, with the given values as its
0466        elements.
0467 
0468         For each parameter P:
0469 
0470         - If P is an expression, P is moved into the result if P is an
0471        rvalue and captured by reference into the result otherwise.
0472 
0473         - Otherwise, P is wrapped in a terminal expression.
0474 
0475         \note <code>make_expression()</code> is only valid if the number of
0476         parameters passed is appropriate for \a Kind.
0477     */
0478     template<
0479         template<expr_kind, class> class ExprTemplate,
0480         expr_kind Kind,
0481         typename... T>
0482     constexpr auto make_expression(T &&... t)
0483     {
0484         constexpr detail::expr_arity arity = detail::arity_of<Kind>();
0485         static_assert(
0486             (arity == detail::expr_arity::one && sizeof...(T) == 1) ||
0487                 (arity == detail::expr_arity::two && sizeof...(T) == 2) ||
0488                 (arity == detail::expr_arity::three && sizeof...(T) == 3) ||
0489                 arity == detail::expr_arity::n,
0490             "The number of parameters passed to make_expression() must "
0491             "match the arity "
0492             "implied by the expr_kind template parameter.");
0493         using tuple_type =
0494             hana::tuple<detail::operand_type_t<ExprTemplate, T>...>;
0495         return ExprTemplate<Kind, tuple_type>{tuple_type{
0496             detail::make_operand<detail::operand_type_t<ExprTemplate, T>>{}(
0497                 static_cast<T &&>(t))...}};
0498     }
0499 
0500     /** Makes a new terminal expression instantiated from the expression
0501         template \a ExprTemplate, with the given value as its sole element.
0502 
0503         \note <code>make_terminal()</code> is only valid if \a T is \b not
0504        an expression.
0505     */
0506     template<template<expr_kind, class> class ExprTemplate, typename T>
0507     constexpr auto make_terminal(T && t)
0508     {
0509         static_assert(
0510             !is_expr<T>::value,
0511             "make_terminal() is only defined for non expressions.");
0512         using result_type = detail::operand_type_t<ExprTemplate, T>;
0513         using tuple_type = decltype(std::declval<result_type>().elements);
0514         return result_type{tuple_type{static_cast<T &&>(t)}};
0515     }
0516 
0517 #ifdef BOOST_NO_CONSTEXPR_IF
0518 
0519     namespace detail {
0520 
0521         template<
0522             template<expr_kind, class> class ExprTemplate,
0523             typename T,
0524             bool IsExpr>
0525         struct as_expr_impl
0526         {
0527             constexpr decltype(auto) operator()(T && t)
0528             {
0529                 return static_cast<T &&>(t);
0530             }
0531         };
0532 
0533         template<template<expr_kind, class> class ExprTemplate, typename T>
0534         struct as_expr_impl<ExprTemplate, T, false>
0535         {
0536             constexpr decltype(auto) operator()(T && t)
0537             {
0538                 return make_terminal<ExprTemplate>(static_cast<T &&>(t));
0539             }
0540         };
0541     }
0542 
0543 #endif
0544 
0545     /** Returns an expression formed from \a t as follows:
0546 
0547         - If \a t is an expression, \a t is forwarded to the caller.
0548 
0549         - Otherwise, \a t is wrapped in a terminal expression.
0550     */
0551     template<template<expr_kind, class> class ExprTemplate, typename T>
0552     constexpr decltype(auto) as_expr(T && t)
0553     {
0554 #ifdef BOOST_NO_CONSTEXPR_IF
0555         return detail::as_expr_impl<ExprTemplate, T, is_expr<T>::value>{}(
0556             static_cast<T &&>(t));
0557 #else
0558         if constexpr (is_expr<T>::value) {
0559             return static_cast<T &&>(t);
0560         } else {
0561             return make_terminal<ExprTemplate>(static_cast<T &&>(t));
0562         }
0563 #endif
0564     }
0565 
0566     /** A callable type that evaluates its contained expression when called.
0567 
0568         \see <code>make_expression_function()</code>
0569     */
0570     template<typename Expr>
0571     struct expression_function
0572     {
0573         template<typename... U>
0574         constexpr decltype(auto) operator()(U &&... u)
0575         {
0576             return ::boost::yap::evaluate(expr, static_cast<U &&>(u)...);
0577         }
0578 
0579         Expr expr;
0580     };
0581 
0582     namespace detail {
0583 
0584         template<expr_kind Kind, typename Tuple>
0585         struct expression_function_expr
0586         {
0587             static const expr_kind kind = Kind;
0588             Tuple elements;
0589         };
0590     }
0591 
0592     /** Returns a callable object that \a expr has been forwarded into. This
0593         is useful for using expressions as function objects.
0594 
0595         Lvalue expressions are stored in the result by reference; rvalue
0596         expressions are moved into the result.
0597 
0598         \note <code>make_expression_function()</code> is only valid if \a
0599         Expr is an expression.
0600     */
0601     template<typename Expr>
0602     constexpr auto make_expression_function(Expr && expr)
0603     {
0604         static_assert(
0605             is_expr<Expr>::value,
0606             "make_expression_function() is only defined for expressions.");
0607         using stored_type =
0608             detail::operand_type_t<detail::expression_function_expr, Expr &&>;
0609         return expression_function<stored_type>{
0610             detail::make_operand<stored_type>{}(static_cast<Expr &&>(expr))};
0611     }
0612 }}
0613 
0614 #include <boost/yap/detail/transform.hpp>
0615 
0616 namespace boost { namespace yap {
0617 
0618     /** Returns a transform object that replaces placeholders within an
0619         expression with the given values.
0620     */
0621     template<typename... T>
0622     constexpr auto replacements(T &&... t)
0623     {
0624         return detail::placeholder_transform_t<T...>(static_cast<T &&>(t)...);
0625     }
0626 
0627     /** Returns \a expr with the placeholders replaced by YAP terminals
0628         containing the given values.
0629 
0630         \note <code>replace_placeholders(expr, t...)</code> is only valid if
0631         \a expr is an expression, and <code>max_p <= sizeof...(t)</code>,
0632         where <code>max_p</code> is the maximum placeholder index in \a expr.
0633     */
0634     template<typename Expr, typename... T>
0635     constexpr decltype(auto) replace_placeholders(Expr && expr, T &&... t)
0636     {
0637         static_assert(
0638             is_expr<Expr>::value,
0639             "evaluate() is only defined for expressions.");
0640         return transform(
0641             static_cast<Expr &&>(expr), replacements(static_cast<T &&>(t)...));
0642     }
0643 
0644     /** Returns a transform object that evaluates an expression using the
0645         built-in semantics.  The transform replaces any placeholders with the
0646         given values.
0647     */
0648     template<typename... T>
0649     constexpr auto evaluation(T &&... t)
0650     {
0651         return detail::evaluation_transform_t<T...>(static_cast<T &&>(t)...);
0652     }
0653 
0654     /** Evaluates \a expr using the built-in semantics, replacing any
0655         placeholders with the given values.
0656 
0657         \note <code>evaluate(expr)</code> is only valid if \a expr is an
0658         expression.
0659     */
0660     template<typename Expr, typename... T>
0661     constexpr decltype(auto) evaluate(Expr && expr, T &&... t)
0662     {
0663         static_assert(
0664             is_expr<Expr>::value,
0665             "evaluate() is only defined for expressions.");
0666         return transform(
0667             static_cast<Expr &&>(expr), evaluation(static_cast<T &&>(t)...));
0668     }
0669 
0670     namespace detail {
0671 
0672         template<typename... Transforms>
0673         constexpr auto make_transform_tuple(Transforms &... transforms)
0674         {
0675             return hana::tuple<Transforms *...>{&transforms...};
0676         }
0677 
0678         template<bool Strict>
0679         struct transform_
0680         {
0681             template<typename Expr, typename Transform, typename... Transforms>
0682             constexpr decltype(auto) operator()(
0683                 Expr && expr, Transform & transform, Transforms &... transforms) const
0684             {
0685                 auto transform_tuple =
0686                     detail::make_transform_tuple(transform, transforms...);
0687                 constexpr expr_kind kind = detail::remove_cv_ref_t<Expr>::kind;
0688                 return detail::
0689                     transform_impl<Strict, 0, kind == expr_kind::expr_ref>{}(
0690                         static_cast<Expr &&>(expr), transform_tuple);
0691             }
0692         };
0693     }
0694 
0695     /** Returns the result of transforming (all or part of) \a expr using
0696         whatever overloads of <code>Transform::operator()</code> match \a
0697         expr.
0698 
0699         \note Transformations can do anything: they may have side effects;
0700         they may mutate values; they may mutate types; and they may do any
0701         combination of these.
0702     */
0703     template<typename Expr, typename Transform, typename... Transforms>
0704     constexpr decltype(auto)
0705     transform(Expr && expr, Transform && transform, Transforms &&... transforms)
0706     {
0707         static_assert(
0708             is_expr<Expr>::value,
0709             "transform() is only defined for expressions.");
0710         return detail::transform_<false>{}(
0711             static_cast<Expr &&>(expr), transform, transforms...);
0712     }
0713 
0714     /** Returns the result of transforming \a expr using whichever overload of
0715         <code>Transform::operator()</code> best matches \a expr.  If no
0716         overload of <code>Transform::operator()</code> matches, a compile-time
0717         error results.
0718 
0719         \note Transformations can do anything: they may have side effects;
0720         they may mutate values; they may mutate types; and they may do any
0721         combination of these.
0722     */
0723     template<typename Expr, typename Transform, typename... Transforms>
0724     constexpr decltype(auto) transform_strict(
0725         Expr && expr, Transform && transform, Transforms &&... transforms)
0726     {
0727         static_assert(
0728             is_expr<Expr>::value,
0729             "transform() is only defined for expressions.");
0730         return detail::transform_<true>{}(
0731             static_cast<Expr &&>(expr), transform, transforms...);
0732     }
0733 
0734 }}
0735 
0736 #endif