Skip to content

Instantly share code, notes, and snippets.

@rhysd
Created December 13, 2012 09:20
Show Gist options
  • Save rhysd/4275201 to your computer and use it in GitHub Desktop.
Save rhysd/4275201 to your computer and use it in GitHub Desktop.
representation for expression tree using boost::variant
#include <iostream>
#include <string>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/apply_visitor.hpp>
struct add_tag{ static char const* symbol(){ static char const* s = "+"; return s; } };
struct sub_tag{ static char const* symbol(){ static char const* s = "-"; return s; } };
struct mul_tag{ static char const* symbol(){ static char const* s = "*"; return s; } };
struct div_tag{ static char const* symbol(){ static char const* s = "/"; return s; } };
template<class Op>
struct binary_operator;
typedef boost::variant< double
, boost::recursive_wrapper<binary_operator<add_tag> >
, boost::recursive_wrapper<binary_operator<sub_tag> >
, boost::recursive_wrapper<binary_operator<mul_tag> >
, boost::recursive_wrapper<binary_operator<div_tag> >
> expression;
template<class Op>
struct binary_operator {
expression left;
expression right;
binary_operator(expression const& lhs, expression const& rhs)
: left(lhs), right(rhs){}
};
struct calculator : public boost::static_visitor<double>{
double operator()(double const constant) const
{
return constant;
}
double operator()(binary_operator<add_tag> const& op) const
{
return boost::apply_visitor( calculator(), op.left )
+ boost::apply_visitor( calculator(), op.right );
}
double operator()(binary_operator<sub_tag> const& op) const
{
return boost::apply_visitor( calculator(), op.left )
- boost::apply_visitor( calculator(), op.right );
}
double operator()(binary_operator<mul_tag> const& op) const
{
return boost::apply_visitor( calculator(), op.left )
* boost::apply_visitor( calculator(), op.right );
}
double operator()(binary_operator<div_tag> const& op) const
{
return boost::apply_visitor( calculator(), op.left )
/ boost::apply_visitor( calculator(), op.right );
}
};
inline double calc( expression const& expr )
{
return boost::apply_visitor(calculator(), expr);
}
struct stringizer : public boost::static_visitor<std::string>{
std::string operator()(double const constant) const
{
return std::to_string(constant);
}
template<class Op>
std::string operator()(binary_operator<Op> const& op) const
{
return '(' + boost::apply_visitor(stringizer(), op.left)
+ Op::symbol()
+ boost::apply_visitor(stringizer(), op.right) + ')';
}
};
inline std::string stringize(expression const& expr)
{
return boost::apply_visitor(stringizer(), expr);
}
int main()
{
expression result(binary_operator<div_tag>(
binary_operator<add_tag>(
binary_operator<sub_tag>(7, 3)
, binary_operator<mul_tag>(2, 3)
)
, 3)
);
std::cout << stringize(result) << " = " << calc(result) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment