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 //[ calc3
7 #include <boost/yap/expression.hpp>
8
9 #include <boost/hana/maximum.hpp>
10
11 #include <iostream>
12
13
14 // Look! A transform! This one transforms the expression tree into the arity
15 // of the expression, based on its placeholders.
16 //[ calc3_get_arity_xform
17 struct get_arity
18 {
19 // Base case 1: Match a placeholder terminal, and return its arity as the
20 // result.
21 template <long long I>
operator ()get_arity22 boost::hana::llong<I> operator() (boost::yap::expr_tag<boost::yap::expr_kind::terminal>,
23 boost::yap::placeholder<I>)
24 { return boost::hana::llong_c<I>; }
25
26 // Base case 2: Match any other terminal. Return 0; non-placeholders do
27 // not contribute to arity.
28 template <typename T>
operator ()get_arity29 auto operator() (boost::yap::expr_tag<boost::yap::expr_kind::terminal>, T &&)
30 {
31 using namespace boost::hana::literals;
32 return 0_c;
33 }
34
35 // Recursive case: Match any expression not covered above, and return the
36 // maximum of its children's arities.
37 template <boost::yap::expr_kind Kind, typename... Arg>
operator ()get_arity38 auto operator() (boost::yap::expr_tag<Kind>, Arg &&... arg)
39 {
40 return boost::hana::maximum(
41 boost::hana::make_tuple(
42 boost::yap::transform(
43 boost::yap::as_expr(std::forward<Arg>(arg)),
44 get_arity{}
45 )...
46 )
47 );
48 }
49 };
50 //]
51
main()52 int main ()
53 {
54 using namespace boost::yap::literals;
55
56 // These lambdas wrap our expressions as callables, and allow us to check
57 // the arity of each as we call it.
58
59 auto expr_1 = 1_p + 2.0;
60
61 auto expr_1_fn = [expr_1](auto &&... args) {
62 auto const arity = boost::yap::transform(expr_1, get_arity{});
63 static_assert(arity.value == sizeof...(args), "Called with wrong number of args.");
64 return evaluate(expr_1, args...);
65 };
66
67 auto expr_2 = 1_p * 2_p;
68
69 auto expr_2_fn = [expr_2](auto &&... args) {
70 auto const arity = boost::yap::transform(expr_2, get_arity{});
71 static_assert(arity.value == sizeof...(args), "Called with wrong number of args.");
72 return evaluate(expr_2, args...);
73 };
74
75 auto expr_3 = (1_p - 2_p) / 2_p;
76
77 auto expr_3_fn = [expr_3](auto &&... args) {
78 auto const arity = boost::yap::transform(expr_3, get_arity{});
79 static_assert(arity.value == sizeof...(args), "Called with wrong number of args.");
80 return evaluate(expr_3, args...);
81 };
82
83 // Displays "5"
84 std::cout << expr_1_fn(3.0) << std::endl;
85
86 // Displays "6"
87 std::cout << expr_2_fn(3.0, 2.0) << std::endl;
88
89 // Displays "0.5"
90 std::cout << expr_3_fn(3.0, 2.0) << std::endl;
91
92 // Static-asserts with "Called with wrong number of args."
93 //std::cout << expr_3_fn(3.0) << std::endl;
94
95 // Static-asserts with "Called with wrong number of args."
96 //std::cout << expr_3_fn(3.0, 2.0, 1.0) << std::endl;
97
98 return 0;
99 }
100 //]
101