#include <iostream>
#include <boost/proto/core.hpp>
#include <boost/proto/transform.hpp>
#include <boost/proto/debug.hpp>
#include <boost/fusion/include/for_each.hpp>
namespace proto = boost::proto;
using proto::_;
template<typename Expr>
struct calculator_expression;
struct calculator_domain
: proto::domain<proto::generator<calculator_expression> >
{
};
struct tag_subexpression
{
template<typename Expr>
void operator()(Expr const& e) const
{
e.is_top_level = 0;
}
};
struct value;
template<typename Expr>
struct calculator_expression
: proto::extends<Expr, calculator_expression<Expr>, calculator_domain>
{
template<typename Xpr>
explicit calculator_expression(
Xpr const &expr = Xpr(),
typename boost::disable_if<
boost::mpl::and_<
proto::is_expr<Xpr>,
boost::mpl::not_<
boost::is_same<typename proto::tag_of<Xpr>::type, proto::tag::terminal>
>
>
>::type* = 0
)
: calculator_expression::proto_extends(expr), is_top_level(0)
{
}
template<typename Xpr>
explicit calculator_expression(
Xpr const &expr = Xpr(),
typename boost::enable_if<
boost::mpl::and_<
proto::is_expr<Xpr>,
boost::mpl::not_<
boost::is_same<typename proto::tag_of<Xpr>::type, proto::tag::terminal>
>
>
>::type* = 0
)
: calculator_expression::proto_extends(expr), is_top_level(1)
{
boost::fusion::for_each(expr, tag_subexpression());
}
BOOST_PROTO_EXTENDS_USING_ASSIGN(calculator_expression)
operator value() const;
~calculator_expression()
{
if(is_top_level)
evaluate(*this);
}
mutable bool is_top_level;
};
struct value
: calculator_expression<proto::terminal<int>::type>
{
typedef calculator_expression<proto::terminal<int>::type> base_type;
value(int e)
: base_type(proto::make_expr<proto::tag::terminal>(e))
{
}
template<typename Expr>
typename proto::result_of::make_expr<
proto::tag::assign,
base_type&,
Expr const&
>::type
operator=(Expr const& e)
{
return static_cast<base_type&>(*this) = e;
}
};
template<typename Expr>
value evaluate(Expr const& e)
{
return proto::_default<>()(e);
}
template<typename Expr>
calculator_expression<Expr>::operator value() const
{
value v(evaluate(*this));
is_top_level = 0;
return v;
}
void bar(const value& v);
int foo()
{
value a = 1;
value b = 2;
bar(b = b += a * 2);
}