#include #include using namespace std; namespace bp = boost::proto; namespace pt = boost::proto::tag; namespace pr = bp::result_of; //////////////////////////////////////////////////////////////////////////////// // Domain //////////////////////////////////////////////////////////////////////////////// struct cmplx_domain; //////////////////////////////////////////////////////////////////////////////// // Grammar //////////////////////////////////////////////////////////////////////////////// struct C_grammar : bp::or_< bp::terminal > , bp::and_< bp::nary_expr< bp::_ , bp::vararg > , bp::not_< bp::address_of > > > {}; //////////////////////////////////////////////////////////////////////////////// // Context //////////////////////////////////////////////////////////////////////////////// template struct cmplx_context : bp::callable_context< cmplx_context const > { typedef std::pair result_type; result_type const& operator()(pt::terminal,result_type const& c) const { return c; } template result_type operator()(pt::plus, L const& l, R const& r) const { return result_type(l.real()+r.real(),l.imag()+r.imag()); } }; //////////////////////////////////////////////////////////////////////////////// // Some trasnform for the C_base grammar //////////////////////////////////////////////////////////////////////////////// struct first_ : bp::callable { template struct result; template struct result { typedef typename boost::remove_reference::type::first_type type; }; }; //////////////////////////////////////////////////////////////////////////////// // Find base for a cmpxl_expr //////////////////////////////////////////////////////////////////////////////// struct C_base : bp::or_< bp::when >, first_(bp::_value)> , bp::when,float()> , bp::_ > {}; //////////////////////////////////////////////////////////////////////////// // Here is the domain-specific expression wrapper, which overrides // real() and imag() to evaluate the expression using the cmplx_context. //////////////////////////////////////////////////////////////////////////// template struct cmplx_expr { typedef typename boost::result_of::type value_type; typedef cmplx_context ctx; BOOST_PROTO_EXTENDS(X, cmplx_expr, cmplx_domain) typename ctx::result_type value() const { return bp::eval(*this,ctx()); } value_type real() const { return value().first; } value_type imag() const { return value().second; } }; //////////////////////////////////////////////////////////////////////////// // Tell proto that in the complex_domain, all // expressions should be wrapped in laxy_vector_expr<> //////////////////////////////////////////////////////////////////////////// struct cmplx_domain : bp::domain,C_grammar> {}; //////////////////////////////////////////////////////////////////////////////// // The cmplx entity itself //////////////////////////////////////////////////////////////////////////////// template struct cmplx : cmplx_expr >::type> { typedef T value_type; typedef typename bp::terminal< std::pair >::type expr_type; cmplx() { bp::value(*this).first = 0; bp::value(*this).second = 0; } cmplx( T const& r, T const& i = T() ) { bp::value(*this).first = r; bp::value(*this).second = i; } template cmplx(Expr const & expr) { affect(expr); } T real() const { return bp::value(*this).first; } T imag() const { return bp::value(*this).second; } T& real() { return bp::value(*this).first; } T& imag() { return bp::value(*this).second; } template cmplx& operator=(Expr const & expr) { bp::value(*this) = x.value(); return *this; } }; // Compiled with : // icpc -Wall -fexceptions -O2 -w1 -I/usr/local/include/boost-1_37/ -c main.cpp -o main.o int main() { cmplx z,u,v; // ICC 10.1 says : // error: no operator "+" matches these operands // operand types are: cmplx + cmplx // z = u+v; z = u+v; return 0; }