#include #include #include #include // For printing #include #include #include #include // TODO: For testing. #define BOOST_PROTO17_STREAM_OPERATORS // TODO: For testing. // TODO: Verbose debugging mode for matching. // TODO: Proto-style "Fuzzy and Exact Matches of Terminals". namespace boost::proto17 { enum class expr_kind { terminal, placeholder, plus, minus, // etc... }; template struct expression; template using terminal = expression; #define BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN(expr) \ noexcept(noexcept(expr)) -> decltype(expr) { return expr; } namespace adl_detail { template constexpr auto eval_plus (T && t, U && u) BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN( static_cast(t) + static_cast(u) ) struct eval_plus_fn { template constexpr auto operator() (T && t, U && u) const BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN( eval_plus(static_cast(t), static_cast(u)) ) }; template constexpr auto eval_minus (T && t, U && u) BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN( static_cast(t) - static_cast(u) ) struct eval_minus_fn { template constexpr auto operator() (T && t, U && u) const BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN( eval_minus(static_cast(t), static_cast(u)) ) }; } #undef BOOST_PROTO17_NOEXCEPT_DECLTYPE_RETURN using adl_detail::eval_plus_fn; using adl_detail::eval_minus_fn; inline namespace function_objects { inline constexpr eval_plus_fn eval_plus{}; inline constexpr eval_minus_fn eval_minus{}; } namespace detail { template struct partial_decay { using type = T; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = T *; }; template struct partial_decay { using type = R(*)(A...); }; template struct partial_decay { using type = R(*)(A..., ...); }; template ::type, bool AddRValueRef = std::is_same_v && !std::is_const_v> struct rhs_value_type_phase_1; template struct rhs_value_type_phase_1 { using type = U &&; }; template struct rhs_value_type_phase_1 { using type = U; }; template struct is_expr { static bool const value = false; }; template struct is_expr> { static bool const value = true; }; template ::type, bool RemoveRefs = std::is_rvalue_reference_v, bool IsExpr = is_expr>::value> struct rhs_type; template struct rhs_type { using type = std::remove_cv_t>; }; template struct rhs_type { using type = terminal>; }; template struct rhs_type { using type = terminal; }; constexpr bool is_hana_llong (...) { return false; } template constexpr bool is_hana_llong(hana::basic_type>) { return true; }; // TODO: Fix. template auto get_tuple_element(Tuple && tuple, hana::tuple>) { return hana::at_c(tuple); }; template auto default_eval_expr (expression const & expr, Tuple && tuple) { using namespace hana::literals; if constexpr (Kind == expr_kind::terminal) { static_assert(sizeof...(T) == 1); return expr.elements[0_c]; } else if constexpr (Kind == expr_kind::placeholder) { static_assert(sizeof...(T) == 1); // TODO: Fix. return get_tuple_element(tuple, expr.elements); } else if constexpr (Kind == expr_kind::plus) { return eval_plus( default_eval_expr(expr.elements[0_c], static_cast(tuple)), default_eval_expr(expr.elements[1_c], static_cast(tuple)) ); } else if constexpr (Kind == expr_kind::minus) { return eval_minus( default_eval_expr(expr.elements[0_c], static_cast(tuple)), default_eval_expr(expr.elements[1_c], static_cast(tuple)) ); } else { assert(false && "Unhandled expr_kind in default_evaluate!"); return; } } } // TODO: Customization point. // TODO: static assert/SFINAE std::is_callable<> // TODO: static assert/SFINAE no placeholders template R evaluate_expression_as (expression const & expr) { return static_cast(detail::default_eval_expr(expr, hana::tuple<>())); } // TODO: static assert/SFINAE std::is_callable<> template auto evaluate (Expr const & expr, T && ...t) { return detail::default_eval_expr(expr, hana::make_tuple(static_cast(t)...)); } template struct expression { using this_type = expression; using tuple_type = hana::tuple; static const expr_kind kind = Kind; expression (T && ... t) : elements (static_cast(t)...) {} expression (hana::tuple const & rhs) : elements (rhs) {} expression (hana::tuple && rhs) : elements (std::move(rhs)) {} expression & operator= (hana::tuple const & rhs) { elements = rhs.elements; } expression & operator= (hana::tuple && rhs) { elements = std::move(rhs.elements); } tuple_type elements; template operator R () { return evaluate_expression_as(*this); } template auto operator+ (U && rhs) const & { using rhs_type = typename detail::rhs_type::type; return expression{ hana::tuple{*this, rhs_type{static_cast(rhs)}} }; } template auto operator+ (U && rhs) && { using rhs_type = typename detail::rhs_type::type; return expression{ hana::tuple{std::move(*this), rhs_type{static_cast(rhs)}} }; } template auto operator- (U && rhs) const & { using rhs_type = typename detail::rhs_type::type; return expression{ hana::tuple{*this, rhs_type{static_cast(rhs)}} }; } template auto operator- (U && rhs) && { using rhs_type = typename detail::rhs_type::type; return expression{ hana::tuple{std::move(*this), rhs_type{static_cast(rhs)}} }; } }; template using placeholder = expression>; namespace literals { template constexpr auto operator"" _p () { using i = hana::llong({c...})>; return expression(i{}); } } 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 std::ostream & print_kind (std::ostream & os, expr_kind kind) { switch (kind) { case expr_kind::plus: return os << "+"; case expr_kind::minus: return os << "-"; // TODO default: return os << "** ERROR: UNKNOWN OPERATOR! **"; } } template auto print_value (std::ostream & os, T const & x) -> decltype(os << x) { return os << x; } inline std::ostream & print_value (std::ostream & os, ...) { return os << "<>"; } template std::ostream & print_type (std::ostream & os) { os << typeindex::type_id().pretty_name(); if (std::is_const_v) os << " const"; if (std::is_volatile_v) os << " volatile"; using no_cv_t = std::remove_cv_t; if (std::is_lvalue_reference_v) os << " &"; if (std::is_rvalue_reference_v) os << " &&"; return os; } template std::ostream & print_impl ( std::ostream & os, expression const & expr, int indent, char const * indent_str) { for (int i = 0; i < indent; ++i) { os << indent_str; } if constexpr (Kind == expr_kind::terminal) { using namespace hana::literals; static_assert(sizeof...(Ts) == 0); os << "term<"; print_type(os); os << ">[="; print_value(os, expr.elements[0_c]); os << "]\n"; } else if constexpr (Kind == expr_kind::placeholder) { using namespace hana::literals; static_assert(sizeof...(Ts) == 0); os << "placeholder<" << (long long)expr.elements[0_c] << ">\n"; } else { os << "expr<"; print_kind(os, Kind); os << ">\n"; hana::for_each(expr.elements, [&os, indent, indent_str](auto const & element) { print_impl(os, element, indent + 1, indent_str); }); } return os; } } template std::ostream & print (std::ostream & os, terminal const & term) { return detail::print_impl(os, term, 0, " "); } template std::ostream & print (std::ostream & os, expression const & expr) { return detail::print_impl(os, expr, 0, " "); } #if defined(BOOST_PROTO17_STREAM_OPERATORS) template std::ostream & operator<< (std::ostream & os, terminal const & term) { return detail::print_impl(os, term, 0, " "); } template std::ostream & operator<< (std::ostream & os, expression const & expr) { return detail::print_impl(os, expr, 0, " "); } #endif 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)); } } } } #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 () { 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, boost::hana::make_tuple(5, 6, 7)); std::cout << "evaluate(unity)=" << result << "\n"; // 1 } { double result = evaluate(expr, boost::hana::make_tuple()); std::cout << "evaluate(expr)=" << result << "\n"; // -41 } { double result = evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15"))); std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // -40 } } namespace test { struct number { explicit operator double () const { return value; } double value; }; // User-defined binary-plus! With weird semantics! inline auto eval_plus (number a, number b) { return number{a.value - b.value}; } } void eval () { 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, boost::hana::make_tuple(5, 6, 7)); std::cout << "evaluate(unity)=" << result << "\n"; // 1 } { double result = (double)evaluate(expr, boost::hana::make_tuple()); std::cout << "evaluate(expr)=" << result << "\n"; // -41 } { double result = (double)evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15"))); std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 42 } } #if 0 void placeholder_eval () { 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, boost::hana::make_tuple(5, 6, 7)); std::cout << "evaluate(p2)=" << result << "\n"; // 7 } { double result = evaluate(expr, boost::hana::make_tuple(std::string("15"), 3, 1)); std::cout << "evaluate(expr)=" << result << "\n"; // 43 } { double result = evaluate(unevaluated_expr, boost::hana::make_tuple(std::string("15"), 2, 3)); std::cout << "evaluate(unevaluated_expr)=" << result << "\n"; // 48 } } #endif int main () { term_plus_x(); term_plus_x_this_ref_overloads(); term_plus_term(); term_plus_expr(); placeholders(); const_term_expr(); print(); default_eval(); eval(); #if 0 // TODO: Fix. placeholder_eval(); #endif #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 }