#include "expression.hpp" #define BOOST_PROTO17_STREAM_OPERATORS // TODO: For testing. #include "print.hpp" #include #include #include #include #include // TODO: Verbose debugging mode for matching. // TODO: Proto-style "Fuzzy and Exact Matches of Terminals". namespace boost::proto17 { namespace match { template struct expression { KindMatches kind_matches; hana::tuple elements; }; // TODO: Use this to detect identical types within a match. template struct placeholder : hana::llong {}; } template constexpr bool is_match_expression (hana::basic_type) { return false; } template constexpr bool is_match_expression (hana::basic_type>) { return true; } namespace literals { template constexpr auto operator"" _T () { return match::placeholder({c...})>{}; } } namespace detail { inline bool matches (...) { return false; } template bool matches (MatchExpr const & match_subtree, TreeExpr const & subtree); template void recursive_match_impl (MatchExpr const & match_subtree, TreeExpr const & subtree, bool & result) { if (!matches(match_subtree[hana::size_c], subtree[hana::size_c])) { result = false; } if constexpr (0 < I) { recursive_match_impl(match_subtree, subtree, result); } } template bool matches (MatchExpr const & match_subtree, TreeExpr const & subtree) { static_assert(is_match_expression(hana::typeid_(match_subtree)), "Attempted to use a non-tree as a match expression."); static_assert(is_expression(hana::typeid_(subtree)), "Attempted to use find a match in a non-tree."); // TODO: Verbose mode. if (!match_subtree.kind_matches(subtree)) { return false; } else { auto constexpr subtree_size = hana::size(subtree.elements); if constexpr (hana::size(match_subtree.elements) != subtree_size) { // TODO: Verbose mode. return false; } else { bool children_match = true; recursive_match_impl( match_subtree.elements, subtree.elements, children_match ); return children_match; } } } template auto mutate_subtrees_of ( Matcher const & match_subtree, expression & tree, Callable && mutation ) { // TODO: Process children first. if (matches(match_subtree, tree)) { return mutation(tree); } else if (Kind == expr_kind::terminal) { return tree; } else { auto mutate_child = [&match_subtree, &mutation] (auto & t) { return mutate_subtrees_of(match_subtree, t, static_cast(mutation)); }; auto return_elements = hana::transform(tree.elements, mutate_child); return make_expression(Kind, std::move(return_elements)); } } } template auto make_terminal (F && f) { return expression{ hana::tuple{static_cast(f)} }; } } #include template using term = boost::proto17::terminal; namespace bp17 = boost::proto17; using namespace std::string_literals; void term_plus_x () { // char const * string { term unity{1.0}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + "3"; } // std::string temporary { term unity{1.0}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + "3"s; } // arrays { term unity{1.0}; int ints[] = {1, 2}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + ints; } { term unity{1.0}; int const ints[] = {1, 2}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + ints; } { term unity{1.0}; int ints[] = {1, 2}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(ints); } // pointers { term unity{1.0}; int ints[] = {1, 2}; int * int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int const ints[] = {1, 2}; int const * int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int ints[] = {1, 2}; int * int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(int_ptr); } // const pointers { term unity{1.0}; int ints[] = {1, 2}; int * const int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int const ints[] = {1, 2}; int const * const int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int ints[] = {1, 2}; int * const int_ptr = ints; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(int_ptr); } // values { term unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term unity{1.0}; int const i = 1; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(i); } } void term_plus_x_this_ref_overloads() { { term unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term const unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term unity{1.0}; int i = 1; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = std::move(unity) + i; } } void term_plus_term () { // char const * string { term unity{1.0}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + term{"3"}; } // std::string temporary { term unity{1.0}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + term{"3"s}; } // pointers { term unity{1.0}; int ints_[] = {1, 2}; term ints = {ints_}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + ints; } { term unity{1.0}; int const ints_[] = {1, 2}; term ints = {ints_}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + ints; } { term unity{1.0}; int ints_[] = {1, 2}; term ints = {ints_}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(ints); } // const pointers { term unity{1.0}; int ints[] = {1, 2}; term int_ptr = {ints}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int const ints[] = {1, 2}; term int_ptr = {ints}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + int_ptr; } { term unity{1.0}; int ints[] = {1, 2}; term int_ptr = {ints}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(int_ptr); } // values { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(i); } // const value terminals { term unity{1.0}; term const i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term unity{1.0}; term const i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } // lvalue refs { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + i; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(i); } // rvalue refs { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(i); } { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > unevaluated_expr = unity + std::move(i); } } void term_plus_expr () { // values { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + expr; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + expr; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + expr; } // const value terminals/expressions { term unity{1.0}; term const i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > const expr = unity + i; bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + expr; } { term unity{1.0}; term i = {1}; bp17::expression< bp17::expr_kind::plus, term, term > const expr = unity + i; bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + expr; } // lvalue refs { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + expr; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + expr; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + expr; } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + i; bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 1; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } // rvalue refs { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 1; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } } void placeholders () { using namespace boost::proto17::literals; { bp17::placeholder<0> p0 = 0_p; } { bp17::placeholder<0> p0 = 0_p; term unity{1.0}; bp17::expression< bp17::expr_kind::plus, bp17::placeholder<0>, term > expr = p0 + unity; } { bp17::placeholder<0> p0 = 0_p; bp17::expression< bp17::expr_kind::plus, bp17::placeholder<0>, bp17::placeholder<1> > expr = p0 + 1_p; } } void const_term_expr () { { term unity{1.0}; int i_ = 42; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } { term const unity{1.0}; int i_ = 42; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } { term unity{1.0}; int i_ = 42; term i{i_}; bp17::expression< bp17::expr_kind::plus, term, term > const expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); } } void print () { term unity{1.0}; int i_ = 42; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); std::cout << "================================================================================\n"; bp17::print(std::cout, unity); std::cout << "================================================================================\n"; bp17::print(std::cout, expr); std::cout << "================================================================================\n"; bp17::print(std::cout, unevaluated_expr); struct thing {}; term a_thing(thing{}); std::cout << "================================================================================\n"; bp17::print(std::cout, a_thing); std::cout << "\n"; std::cout << "================================================================================\n"; std::cout << "================================================================================\n"; { using namespace boost::proto17::literals; std::cout << (0_p + unity); std::cout << (2_p + 3_p); std::cout << (unity + 1_p); } #if defined(BOOST_PROTO17_STREAM_OPERATORS) std::cout << "\n"; std::cout << "================================================================================\n"; std::cout << "================================================================================\n"; std::cout << unity; std::cout << "================================================================================\n"; std::cout << expr; std::cout << "================================================================================\n"; std::cout << unevaluated_expr; std::cout << "================================================================================\n"; std::cout << a_thing; #endif } void default_eval () { std::cout << "\ndefault_eva()\n"; term unity{1.0}; int i_ = 42; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::minus, term, term > expr = unity - std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::minus, term, term > > unevaluated_expr = unity + std::move(expr); { double result = unity; std::cout << "unity=" << result << "\n"; // 1 } { double result = expr; std::cout << "expr=" << result << "\n"; // -41 } { double result = unevaluated_expr; std::cout << "unevaluated_expr=" << result << "\n"; // -40 } { double result = evaluate(unity, 5, 6, 7); std::cout << "evaluate(unity)=" << result << "\n"; // 1 } { double result = evaluate(expr); std::cout << "evaluate(expr)=" << result << "\n"; // -41 } { double result = evaluate(unevaluated_expr, std::string("15")); std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // -40 } std::cout << "\n"; } namespace user { struct number { explicit operator double () const { return value; } double value; }; // User-defined binary-plus! With weird semantics! template inline auto eval_plus (A a, B b) { return number{a.value - b.value}; } template constexpr auto eval_expression_as ( E const & expr, boost::hana::basic_type, T && ...t) { std::cout << "User eval! "; return static_cast( bp17::detail::default_eval_expr( expr, boost::hana::make_tuple(static_cast(t)...) ) ); } } void user_operator_eval () { std::cout << "\nuser_operator_eval()\n"; term unity{{1.0}}; double d_ = 42.0; term i{{d_}}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); { double result = unity; std::cout << "unity=" << result << "\n"; // 1 } { double result = expr; std::cout << "expr=" << result << "\n"; // -41 } { double result = unevaluated_expr; std::cout << "unevaluated_expr=" << result << "\n"; // 42 } { double result = (double)evaluate(unity, 5, 6, 7); std::cout << "evaluate(unity)=" << result << "\n"; // 1 } { double result = (double)evaluate(expr); std::cout << "evaluate(expr)=" << result << "\n"; // -41 } { double result = (double)evaluate(unevaluated_expr, std::string("15")); std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 42 } std::cout << "\n"; } void user_eval_expression_as () { term unity{{1.0}}; double d_ = 42.0; term i{{d_}}; bp17::expression< bp17::expr_kind::plus, term, term > expr = unity + std::move(i); bp17::expression< bp17::expr_kind::plus, term, bp17::expression< bp17::expr_kind::plus, term, term > > unevaluated_expr = unity + std::move(expr); std::cout << "\nuser_eval_expression_as()\n"; { user::number result = unity; std::cout << "unity=" << result.value << "\n"; // 1 } { user::number result = expr; std::cout << "expr=" << result.value << "\n"; // -41 } { user::number result = unevaluated_expr; std::cout << "unevaluated_expr=" << result.value << "\n"; // 42 } { user::number result = evaluate(unity, 5, 6, 7); std::cout << "evaluate(unity)=" << result.value << "\n"; // 1 } { double result = (double)evaluate(expr); std::cout << "evaluate(expr)=" << result << "\n"; // -41 } { double result = (double)evaluate(unevaluated_expr, std::string("15")); std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 42 } { user::number result = bp17::evaluate_as(unity, 5, 6, 7); std::cout << "evaluate(unity)=" << result.value << "\n"; // 1 } { user::number result = bp17::evaluate_as(expr); std::cout << "evaluate(expr)=" << result.value << "\n"; // -41 } { user::number result = bp17::evaluate_as(unevaluated_expr, std::string("15")); std::cout << "evaluate(unevaluated_expr)=" << result.value << "\n"; // 42 } std::cout << "\n"; } void placeholder_eval () { std::cout << "\nplaceholder_eval()\n"; using namespace boost::proto17::literals; bp17::placeholder<2> p2 = 2_p; int i_ = 42; term i{std::move(i_)}; bp17::expression< bp17::expr_kind::plus, bp17::placeholder<2>, term > expr = p2 + std::move(i); bp17::expression< bp17::expr_kind::plus, bp17::placeholder<2>, bp17::expression< bp17::expr_kind::plus, bp17::placeholder<2>, term > > unevaluated_expr = p2 + std::move(expr); { double result = evaluate(p2, 5, 6, 7); std::cout << "evaluate(p2)=" << result << "\n"; // 7 } { double result = evaluate(expr, std::string("15"), 3, 1); std::cout << "evaluate(expr)=" << result << "\n"; // 43 } { double result = evaluate(unevaluated_expr, std::string("15"), 2, 3); std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 48 } std::cout << "\n"; } namespace user { inline auto max (int a, int b) { return a < b ? b : a; }; struct tag_type {}; inline number tag_function (double a, double b) { return number{a + b}; } // User-defined operator() implementation. template inline auto eval_call (F && f, T && ...t) { if constexpr (sizeof...(T) == 2u && std::is_same_v, tag_type>) { return tag_function((double)t...); } else { assert(!"Unhandled case in eval_call()"); return; } } } void call_expr () { std::cout << "\ncall_expr()\n"; using namespace boost::proto17::literals; { bp17::expression< bp17::expr_kind::call, bp17::placeholder<0>, bp17::placeholder<1>, bp17::placeholder<2> > expr = 0_p(1_p, 2_p); { auto min = [] (int a, int b) { return a < b ? a : b; }; int result = evaluate(expr, min, 3, 7); std::cout << "evaluate(expr, min, 3, 7)=" << result << "\n"; // 3 } { int result = evaluate(expr, &user::max, 3, 7); std::cout << "evaluate(expr, &user::max, 3, 7)=" << result << "\n"; // 7 } { int result = evaluate(expr, user::max, 3, 7); std::cout << "evaluate(expr, user::max, 3, 7)=" << result << "\n"; // 7 } } { auto min_lambda = [] (int a, int b) { return a < b ? a : b; }; { auto min = bp17::make_terminal(min_lambda); auto expr = min(0_p, 1_p); { int result = evaluate(expr, 3, 7); std::cout << "evaluate(expr, 3, 7)=" << result << "\n"; // 3 } } { term min = {{min_lambda}}; auto expr = min(0_p, 1_p); { int result = evaluate(expr, 3, 7); std::cout << "evaluate(expr, 3, 7)=" << result << "\n"; // 3 } } } { struct min_function_object_t { auto operator() (int a, int b) const { return a < b ? a : b; } } min_function_object; { term min = bp17::make_terminal(min_function_object); auto expr = min(0_p, 1_p); { using namespace boost::hana::literals; int result = evaluate(expr, 3, 7); std::cout << "evaluate(expr, 3, 7)=" << result << "\n"; // 3 } } { term min = {{min_function_object}}; auto expr = min(0_p, 1_p); { int result = evaluate(expr, 3, 7); std::cout << "evaluate(expr, 3, 7)=" << result << "\n"; // 3 } } { auto min = bp17::make_terminal(min_function_object_t{}); auto expr = min(0_p, 1_p); { int result = evaluate(expr, 3, 7); std::cout << "evaluate(expr, 3, 7)=" << result << "\n"; // 3 } } { term min = {{min_function_object_t{}}}; auto expr = min(0_p, 1_p); { int result = evaluate(expr, 3, 7); std::cout << "evaluate(expr, 3, 7)=" << result << "\n"; // 3 } } } { auto min_lambda = [] (int a, int b) { return a < b ? a : b; }; { auto min = bp17::make_terminal(min_lambda); auto expr = min(0, 1); { int result = evaluate(expr); std::cout << "evaluate(expr)=" << result << "\n"; // 0 } } { term min = {{min_lambda}}; bp17::expression< bp17::expr_kind::call, term, term, term > expr = min(0, 1); { int result = evaluate(expr); std::cout << "evaluate(expr)=" << result << "\n"; // 0 } } } { { auto plus = bp17::make_terminal(user::tag_type{}); auto expr = plus(user::number{13}, 1); { user::number result = expr; std::cout << "expr=" << result.value << "\n"; // 42 } } { term plus = {{user::tag_type{}}}; bp17::expression< bp17::expr_kind::call, term, term, term > expr = plus(0, 1); { user::number result = expr; std::cout << "expr=" << result.value << "\n"; // 0 } } } std::cout << "\n"; } namespace reference_returning { struct number { double value; }; number const the_result{13.0}; // User-defined binary-plus! With weird reference semantics! template inline number const & eval_plus (A a, B b) { return the_result; } } void reference_returns () { term unity = {{1.0}}; auto expr = unity + reference_returning::number{1.0}; // TODO: This has to fail due to the general implicit declaration rules // (see [conv] 3-6). This needs to be noted in docs. #if 0 { reference_returning::number const & n = expr; if (&n == &reference_returning::the_result) std::cout << "Got the_result.\n"; else std::cout << "FAIL\n"; } #endif { reference_returning::number const & n = evaluate(expr); if (&n == &reference_returning::the_result) std::cout << "Got the_result.\n"; else std::cout << "FAIL\n"; } static_assert( std::is_same_v< decltype(evaluate(expr)), reference_returning::number const & > ); } int main () { term_plus_x(); term_plus_x_this_ref_overloads(); term_plus_term(); term_plus_expr(); placeholders(); const_term_expr(); print(); default_eval(); user_eval_expression_as(); user_operator_eval(); placeholder_eval(); call_expr(); reference_returns(); #if 0 // TODO { bp17::terminal unity{1.0}; auto unevaluated_expr = unity + "3"; auto mutated_expr = mutate(unevaluated_expr, match_expr, mutation); auto result = bp17::eval(unevaluated_expr); } { bp17::terminal a{1.0}; bp17::terminal x{2.0}; bp17::terminal b{3}; auto unevaluated_expr = a * x + b; auto match_expr = 0_T * 0_T + 1_T; auto mutated_expr = mutate(unevaluated_expr, match_expr, mutation); auto result = bp17::eval(mutated_expr); } { bp17::terminal a{1.0}; bp17::terminal x{2.0}; bp17::terminal b{3}; auto match_double_2 = [] (auto && terminal) { if constexpr (hana::typeid_(terminal) == hana::type{}) return terminal == 2.0; else return false; }; auto unevaluated_expr = a * x + b; auto match_expr = bp17::match * match_double_2 + 0_T; auto mutated_expr = mutate(unevaluated_expr, match_expr, mutation); auto result = bp17::eval(mutated_expr); } #endif }