|
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