#include <iostream>
#include <functional>
#include <boost/assert.hpp>
#include <boost/mpl/int.hpp>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
#include <boost/proto/proto_typeof.hpp>
#include <boost/proto/transform.hpp>
namespace mpl = boost::mpl;
namespace proto = boost::proto;
using proto::_;
struct Vec3SubscriptCtx
: proto::callable_context< Vec3SubscriptCtx const >
{
typedef int result_type;
Vec3SubscriptCtx(int i)
: i_(i)
{}
int operator ()(proto::tag::terminal, int const (&arr)[3]) const
{
return arr[this->i_];
}
int i_;
};
struct CountLeavesCtx
: proto::callable_context< CountLeavesCtx, proto::null_context >
{
CountLeavesCtx()
: count(0)
{}
typedef void result_type;
void operator ()(proto::tag::terminal, int const(&)[3])
{
++this->count;
}
int count;
};
struct iplus : std::plus<int>, proto::callable {};
struct CountLeaves
: proto::or_<
proto::when<proto::terminal<int[3]>, mpl::int_<1>() >
, proto::when<proto::terminal<_>, int() >
, proto::otherwise< proto::fold<_, int(), iplus(CountLeaves, proto::_state) > >
>
{};
struct Vec3
: proto::extends<proto::terminal<int[3]>::type, Vec3>
{
explicit Vec3(int i=0, int j=0, int k=0)
{
(*this)[0] = i;
(*this)[1] = j;
(*this)[2] = k;
}
int &operator [](int i)
{
return proto::value(*this)[i];
}
int const &operator [](int i) const
{
return proto::value(*this)[i];
}
template< typename Expr >
Vec3 &operator =(Expr const & expr)
{
typedef Vec3SubscriptCtx const CVec3SubscriptCtx;
(*this)[0] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(0));
(*this)[1] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(1));
(*this)[2] = proto::eval(proto::as_expr(expr), CVec3SubscriptCtx(2));
return *this;
}
Vec3 &operator=(Vec3 const &that)
{
(*this)[0] = that[0];
(*this)[1] = that[1];
(*this)[2] = that[2];
return *this;
}
void print() const
{
std::cout << '{' << (*this)[0]
<< ", " << (*this)[1]
<< ", " << (*this)[2]
<< '}' << std::endl;
}
};
template<typename Expr>
int count_leaves(Expr const &expr)
{
CountLeavesCtx ctx;
proto::eval(expr, ctx);
int i = 0;
BOOST_ASSERT( CountLeaves()(expr, i, i) == ctx.count );
return ctx.count;
}
int main()
{
Vec3 a, b, c;
c = 4;
b[0] = -1;
b[1] = -2;
b[2] = -3;
a = b + c;
a.print();
Vec3 d;
BOOST_PROTO_AUTO(expr1, b + c);
d = expr1;
d.print();
int num = count_leaves(expr1);
std::cout << num << std::endl;
BOOST_PROTO_AUTO(expr2, b + 3 * c);
num = count_leaves(expr2);
std::cout << num << std::endl;
BOOST_PROTO_AUTO(expr3, b + c * d);
num = count_leaves(expr3);
std::cout << num << std::endl;
return 0;
}