Boost logo

Boost :

Subject: [boost] [proto] switch_ with a policy
From: troy d. straszheim (troy_at_[hidden])
Date: 2009-03-25 11:50:16


In some situations you're limited by the fact that proto::switch_
matches on tag type. For instance, if you have a bunch of these things:

namespace tag {
   struct exp {};
   struct log {};
   // lots more, say 50 of them
}

Expression<terminal<tag::exp>::type> const exp = {{}};
Expression<terminal<tag::log>::type> const log = {{}};
// 50 more

And you try to write a transform with switch_ that handles theses,
you're stymied by the fact that switch_ will only tell you the tag of
what has matched. Here's an attempt at the switch:

struct UnaryFunctionCases
{
   template <typename Tag, int i=0>
   struct case_ : not_<_> { };

   template <int i>
   struct case_<VEY, i>
   : when<proto::function<...>, DoSomethingClever(...)>
   { };

};

struct UnaryFunctionSwitch : proto::switch_<UnaryFunctionCases> { };

the VEY above is going to be proto::tag::function for all of these
terminals if you're trying to transform an expression like

   exp(7);

(If I remember correctly... I havent looked at this code in a while).

You can add a policy to the stock switch_ that makes this easy to handle
(sorry if my mailer borks some newlines here):

namespace boost {
   namespace proto {

     template<typename Cases,
             template <class> class Policy = boost::proto::tag_of>
     struct switch_
       : proto::transform<switch_<Cases, Policy> >
     {
       typedef switch_<Cases, Policy> proto_base_expr;

       template<typename Expr, typename State, typename Data>
       struct impl
        : Cases::template case_<

        typename Policy<Expr>::type

>::template impl<Expr, State, Data>
       { };

       template<typename Expr, typename State, typename Data>
       struct impl<Expr &, State, Data>
        : Cases::template case_<
        
        typename Policy<Expr>::type
        
>::template impl<Expr &, State, Data>
       { };
     };

     namespace detail {

       template<typename Expr,
                typename Cases,
                template <class> class Policy>
       struct matches_<Expr, switch_<Cases, Policy> >
        : matches_<
        Expr
        , typename Cases::template case_<
             typename Policy<Expr>::type
>::proto_base_expr
>
       { };
     }
   }
}

Which I believe behaves identically to the stock switch_, and you can
handle the example scenario like this:

namespace detail {

   // metafunction extracts the thing we want to match on
   template <typename Expr>
   struct fncall2fntag
   {
     typedef typename Expr::proto_child0 child0;
     typedef typename proto::result_of::value<child0>::type value;
     typedef typename boost::remove_reference<value>::type noref;
     typedef typename boost::remove_const<noref>::type noconst;
     typedef noconst type;
    };
   }

struct UnaryFunctionCases
{
   template <typename Tag, int _=0>
   struct case_ : proto::not_<proto::_>
   { };

   template <int _> struct case_<tag::exp,_>
   : proto::when<
       proto::function<proto::terminal<tag::exp>, Array>,
       UnaryFunctionDispatch(tag::exp(), ...)
> { };

    // etc
};

struct UnaryFunctionSwitch
: proto::switch_<UnaryFunctionCases, detail::fncall2fntag>
{ };

Thoughts?

-t


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk