#include <iostream>
#include <boost/mpl/int.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
struct TArrayGrammar
: proto::or_<
proto::terminal< int >
, proto::terminal< int[3] >
, proto::plus< TArrayGrammar, TArrayGrammar >
, proto::minus< TArrayGrammar, TArrayGrammar >
, proto::multiplies< TArrayGrammar, TArrayGrammar >
, proto::divides< TArrayGrammar, TArrayGrammar >
>
{};
template<typename Expr>
struct TArrayExpr;
struct TArrayDomain
: proto::domain<proto::generator<TArrayExpr>, TArrayGrammar>
{};
struct TArraySubscriptCtx
: proto::callable_context< TArraySubscriptCtx const >
{
typedef int result_type;
TArraySubscriptCtx(std::ptrdiff_t i)
: i_(i)
{}
int operator ()(proto::tag::terminal, int const (&data)[3]) const
{
return data[this->i_];
}
std::ptrdiff_t i_;
};
struct TArrayPrintCtx
: proto::callable_context< TArrayPrintCtx const >
{
typedef std::ostream &result_type;
TArrayPrintCtx() {}
std::ostream &operator ()(proto::tag::terminal, int i) const
{
return std::cout << i;
}
std::ostream &operator ()(proto::tag::terminal, int const (&arr)[3]) const
{
return std::cout << '{' << arr[0] << ", " << arr[1] << ", " << arr[2] << '}';
}
template<typename L, typename R>
std::ostream &operator ()(proto::tag::plus, L const &l, R const &r) const
{
return std::cout << '(' << l << " + " << r << ')';
}
template<typename L, typename R>
std::ostream &operator ()(proto::tag::minus, L const &l, R const &r) const
{
return std::cout << '(' << l << " - " << r << ')';
}
template<typename L, typename R>
std::ostream &operator ()(proto::tag::multiplies, L const &l, R const &r) const
{
return std::cout << l << " * " << r;
}
template<typename L, typename R>
std::ostream &operator ()(proto::tag::divides, L const &l, R const &r) const
{
return std::cout << l << " / " << r;
}
};
template<typename Expr>
struct TArrayExpr
: proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain>
{
typedef proto::extends<Expr, TArrayExpr<Expr>, TArrayDomain> base_type;
TArrayExpr( Expr const & expr = Expr() )
: base_type( expr )
{}
int operator []( std::ptrdiff_t i ) const
{
TArraySubscriptCtx const ctx(i);
return proto::eval(*this, ctx);
}
friend std::ostream &operator <<(std::ostream &sout, TArrayExpr<Expr> const &expr)
{
TArrayPrintCtx const ctx;
return proto::eval(expr, ctx);
}
};
struct TArray
: TArrayExpr< proto::terminal< int[3] >::type >
{
explicit TArray( int i = 0, int j = 0, int k = 0 )
{
(*this)[0] = i;
(*this)[1] = j;
(*this)[2] = k;
}
int &operator [](std::ptrdiff_t i)
{
return proto::value(*this)[i];
}
int const &operator [](std::ptrdiff_t i) const
{
return proto::value(*this)[i];
}
template< typename Expr >
TArray &operator =(Expr const & expr)
{
return this->assign(proto::as_expr<TArrayDomain>(expr));
}
template< typename Expr >
TArray &printAssign(Expr const & expr)
{
*this = expr;
std::cout << *this << " = " << expr << std::endl;
return *this;
}
private:
template< typename Expr >
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;
}