• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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