#include "expression.hpp" #include #include template struct tarray_expr; struct take_nth { boost::proto17::terminal operator() (boost::proto17::terminal, tarray_expr> const & expr); std::size_t n; }; template struct tarray_expr { static_assert( Kind != boost::proto17::expr_kind::terminal || std::is_same>{} || std::is_same>>{} ); using this_type = tarray_expr; static const boost::proto17::expr_kind kind = Kind; Tuple elements; BOOST_PROTO17_USER_BINARY_OPERATOR_MEMBER(plus, this_type, ::tarray_expr) BOOST_PROTO17_USER_BINARY_OPERATOR_MEMBER(minus, this_type, ::tarray_expr) BOOST_PROTO17_USER_BINARY_OPERATOR_MEMBER(multiplies, this_type, ::tarray_expr) BOOST_PROTO17_USER_BINARY_OPERATOR_MEMBER(divides, this_type, ::tarray_expr) int operator[] (std::size_t n) const { return boost::proto17::evaluate(boost::proto17::transform(*this, take_nth{n})); } }; BOOST_PROTO17_USER_NON_MEMBER_BINARY_OPERATOR(plus, ::tarray_expr) BOOST_PROTO17_USER_NON_MEMBER_BINARY_OPERATOR(minus, ::tarray_expr) BOOST_PROTO17_USER_NON_MEMBER_BINARY_OPERATOR(multiplies, ::tarray_expr) BOOST_PROTO17_USER_NON_MEMBER_BINARY_OPERATOR(divides, ::tarray_expr) boost::proto17::terminal take_nth::operator() (boost::proto17::terminal, tarray_expr> const & expr) { int const x = boost::proto17::value(expr)[n]; return boost::proto17::make_terminal(x); } std::ostream & operator<< (std::ostream & os, boost::proto17::terminal expr) { return os << '{' << boost::proto17::value(expr) << '}'; } std::ostream & operator<< (std::ostream & os, boost::proto17::terminal, tarray_expr> expr) { std::array const & a = boost::proto17::value(expr); return os << '{' << a[0] << ", " << a[1] << ", " << a[2] << '}'; } template std::ostream & operator<< (std::ostream & os, tarray_expr const & expr) { return os << boost::proto17::value(expr); } template std::ostream & operator<< (std::ostream & os, tarray_expr const & expr) { if (Kind == boost::proto17::expr_kind::plus || Kind == boost::proto17::expr_kind::minus) os << '('; os << boost::proto17::left(expr) << " " << op_string(Kind) << " " << boost::proto17::right(expr); if (Kind == boost::proto17::expr_kind::plus || Kind == boost::proto17::expr_kind::minus) os << ')'; return os; } struct TArray : tarray_expr< boost::proto17::expr_kind::terminal, boost::hana::tuple> > { explicit TArray (int i = 0, int j = 0, int k = 0) { (*this)[0] = i; (*this)[1] = j; (*this)[2] = k; } explicit TArray (std::array a) { (*this)[0] = a[0]; (*this)[1] = a[1]; (*this)[2] = a[2]; } int & operator[] (std::ptrdiff_t i) { return boost::proto17::value(*this)[i]; } int const & operator[] (std::ptrdiff_t i) const { return boost::proto17::value(*this)[i]; } TArray & operator= (int i) { return assign(TArray(i)); } template TArray & operator= (Expr const & expr) { if constexpr (Expr::kind == boost::proto17::expr_kind::terminal) { return assign(TArray(boost::proto17::value(expr))); } else { return assign(expr); } } template TArray & printAssign (Expr const & expr) { *this = expr; std::cout << *this << " = " << expr << std::endl; return *this; } private: template TArray & assign (Expr const & expr) { (*this)[0] = expr[0]; (*this)[1] = expr[1]; (*this)[2] = expr[2]; return *this; } }; int main() { TArray a(3,1,2); TArray b; std::cout << a << std::endl; std::cout << b << std::endl; b[0] = 7; b[1] = 33; b[2] = -99; TArray c(a); std::cout << c << std::endl; a = 0; std::cout << a << std::endl; std::cout << b << std::endl; std::cout << c << std::endl; a = b + c; std::cout << a << std::endl; a.printAssign(b+c*(b + 3*c)); return 0; }