#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/context.hpp>
namespace proto = boost::proto;
using proto::_;
template<typename Expr>
struct calculator_expression;
struct calculator_domain
: proto::domain<proto::generator<calculator_expression> >
{};
template<int I> struct placeholder {};
struct calculator_context
: proto::callable_context< calculator_context const >
{
double d[2];
typedef double result_type;
explicit calculator_context(double d1 = 0., double d2 = 0.)
{
d[0] = d1;
d[1] = d2;
}
template<int I>
double operator ()(proto::tag::terminal, placeholder<I>) const
{
return d[ I - 1 ];
}
};
template<typename Expr>
struct calculator_expression
: proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
explicit calculator_expression(Expr const &expr = Expr())
: calculator_expression::proto_extends(expr)
{}
BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression<Expr>)
double operator ()() const
{
calculator_context const ctx;
return proto::eval(*this, ctx);
}
double operator ()(double d1) const
{
calculator_context const ctx(d1);
return proto::eval(*this, ctx);
}
double operator ()(double d1, double d2) const
{
calculator_context const ctx(d1, d2);
return proto::eval(*this, ctx);
}
};
calculator_expression<proto::terminal< placeholder< 1 > >::type> const _1;
calculator_expression<proto::terminal< placeholder< 2 > >::type> const _2;
int main()
{
std::cout << (_1 + 2.0)( 3.0 ) << std::endl;
std::cout << ( _1 * _2 )( 3.0, 2.0 ) << std::endl;
std::cout << ( (_1 - _2) / _2 )( 3.0, 2.0 ) << std::endl;
return 0;
}