#include namespace proto = boost::proto; namespace mpl = boost::mpl; typedef proto::terminal int_terminal; typedef proto::terminal double_terminal; //////////////////////////////////////////////////////////////////////////////// template struct actor1; struct grammar1; // define our base domain struct domain1 : proto::domain< proto::pod_generator , grammar1 , proto::default_domain > {}; // define the grammar for that domain struct grammar1 : proto::switch_ { // The actual grammar is parametrized on a Grammar parameter as well // This allows us to effectively reuse that grammar in subdomains. template struct case_ : proto::or_< proto::plus , int_terminal > {}; }; // boring expression wrapper template struct actor1 { BOOST_PROTO_BASIC_EXTENDS(Expr, actor1, domain1) }; //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// template struct actor2; struct grammar2; // our domain2 ... this is a subdomain of domain1 struct domain2 : proto::domain< proto::pod_generator , grammar2 , domain1 > {}; // the grammar2 struct grammar2 : proto::switch_ { // again parameterized on a Grammar, defaulting to grammar2 // This is not really needed here, but allows to reuse that grammar as well template struct case_ : proto::or_< // here we go ... reuse grammar1::case_ with our new grammar grammar1::case_ , double_terminal > {}; }; // boring expression wrapper template struct actor2 { BOOST_PROTO_BASIC_EXTENDS(Expr, actor2, domain2) }; //////////////////////////////////////////////////////////////////////////////// actor1 t1 = {{42}}; actor2 t2 = {{3.14}}; //////////////////////////////////////////////////////////////////////////////// // specialize is_extension trait, so actor1 and actor2 don't get picked up // by proto's default operators. // otherwise, expression like t1 + t2 would not work. namespace boost { namespace proto { template struct is_extension > : mpl::false_ {}; template struct is_extension > : mpl::false_ {}; }} // define a trait which marks the actors as special classes template struct is_actor : boost::mpl::false_ {}; template struct is_actor > : boost::mpl::true_ {}; template struct is_actor > : boost::mpl::true_ {}; template struct is_super_domain; template struct is_super_domain : mpl::eval_if< boost::is_same , mpl::true_ , is_super_domain > {}; template struct is_super_domain : mpl::true_ {}; template struct is_super_domain : mpl::false_ {}; // strongest domain selects the most specialised domain // meaning that if: // 1. D0 is a super domain of D1, D1 is the strongest // 2. D1 is a super domain of D0, D0 is the strongest // 3. if 1 and 2 are false, the common domain is selected. template struct strongest_domain2_impl : boost::mpl::eval_if< typename is_super_domain::type//boost::is_same , boost::mpl::identity , boost::mpl::eval_if< typename is_super_domain::type//boost::is_same , boost::mpl::identity , proto::detail::common_domain2 > > {}; template struct strongest_domain1 : proto::domain_of {}; template struct strongest_domain2 : strongest_domain2_impl< typename proto::domain_of::type , typename proto::domain_of::type > {}; //////////////////////////////////////////////////////////////////////////////// // Extension to proto to select the strongest domain, as described below. struct strongest_domain : proto::domain< proto::detail::not_a_generator , proto::detail::not_a_grammar , proto::detail::not_a_domain > {}; namespace boost { namespace proto { namespace detail { template struct enable_unary : enable_unary< typename strongest_domain1::type , typename strongest_domain1::type::proto_grammar , Trait , Tag , Expr > {}; template struct enable_binary : enable_binary< typename strongest_domain2::type , typename strongest_domain2::type::proto_grammar , Trait , Tag , Left , Right > {}; template struct make_expr_ : make_expr_< Tag , typename strongest_domain1::type , A0 > {}; template struct make_expr_ : make_expr_< Tag , typename strongest_domain2::type , A0 , A1 > {}; } }} //////////////////////////////////////////////////////////////////////////////// // define operators for that kind of classes, we do not want the deduced domain // but the strongest domain. // Meaning: // For "actor1 + actor2" the result must be in domain2, not domain1 // as deduce_domain would calculate the resulting domain. // If the resulting domain is domain1, the resulting expression would not match // the grammar of domain1 ... BOOST_PROTO_DEFINE_OPERATORS(is_actor, strongest_domain) //////////////////////////////////////////////////////////////////////////////// template void test(T const & t) { std::cout << typeid(T).name() << "\n"; std::cout << std::boolalpha; std::cout << " matches grammar1? " << proto::matches::type::value << "\n"; std::cout << " matches grammar2? " << proto::matches::type::value << "\n"; } template void test(T0 const& t0, T1 const& t1) { test(t0 + t1); test(t1 + t0); std::cout << "\n"; } template void test(T0 const& t0, T1 const& t1, T2 const& t2) { test(t0 + t1, t2); test(t1 + t0, t2); test(t1 + t2, t0); test(t2 + t1, t0); test(t0 + t2, t1); test(t2 + t0, t1); std::cout << "\n"; } int main() { test(t1); test(t2); test(t1, t1); test(t2, t2); test(t1, t2); test(t1, t1, t1); test(t2, t1, t1); test(t1, t2, t1); test(t1, t1, t2); test(t2, t2, t1); test(t2, t1, t2); test(t1, t2, t2); test(t2, t2, t2); }