|
Boost Users : |
Subject: [Boost-users] [proto] Matching grammars in the presence of adapted types
From: Sebastian Redl (sebastian.redl_at_[hidden])
Date: 2010-06-04 11:05:05
Hi,
First off, this whole thing uses Boost 1.42.
I'm trying to define arithmetic types where some expression patterns will
be matched and replaced by something else (e.g. a & ~b, the andnot
pattern). The whole thing is a proof-of-concept and teach-myself-proto
thing that should eventually do SIMD operations. Right now, though, it
simply wraps integers.
First I tried defining my type as a proto type this way:
-----------------
template <typename Expr>
class simd_expr : public proto::extends<Expr, simd_expr<Expr>,
simd_domain> { /* as in the tutorial */ };
class smartint : public simd_expr<proto::terminal<smartint>::type> {
int value;
// ...
};
inline smartint ilit(int i) { return smartint(i); }
-----------------
However, this didn't work, because at the instantiation point of
simd_expr<proto::terminal<smartint>::type>, smartint is incomplete, and
something in proto doesn't like that.
So I used the only thing in the docs that looked like my use case, and did
the non-intrusive adapting thing demonstrated on the matrix and vector
classes.
-----------------
class smartint { ... };
template <typename T> struct is_terminal : mpl::false_ {};
template <> struct is_terminal<smartint> : mpl::true_ {};
BOOST_PROTO_DEFINE_OPERATORS(is_terminal, simd_domain)
-----------------
This works nicely for normal evaluations. I have a simd_context, which
knows how to evaluate smartint, and forwards everything else to
default_context:
-----------------
struct simd_context :
proto::callable_context<simd_context const, proto::default_context>
{
typedef int result_type;
int operator ()(proto::tag::terminal, smartint const &si) const;
};
inline int simd_context::operator ()(
proto::tag::terminal,
smartint const &si) const
{
return si.get();
}
-----------------
Now I can do fun stuff like this:
-----------------
int i = ilit(7) + 3; // simd_expr has 'operator int'
-----------------
Now I want to match specific expression patterns and do something special
for them. For example, in this expression:
-----------------
i = 1 * (0xF0 & ~ilit(0x70));
-----------------
I want to match the 'a & ~b' pattern and treat it specially. So first, I
define this pattern as a grammar:
-----------------
struct andnot_pattern :
proto::bitwise_and<proto::_, proto::complement<proto::_>>
{};
-----------------
And then I add another function to my context that applies only to
expressions matching this pattern:
-----------------
template <typename Tag, typename Expr>
typename boost::enable_if<
proto::matches<Expr, andnot_pattern>,
int>::type
operator ()(Tag, Expr const &e) const
{
std::cerr << "Found andnot pattern\n";
return 0xFF;
}
-----------------
However, when I try to compile this, VC++ 2010 complains:
boost_1_42_0\boost\proto\matches.hpp(502): error C2039: 'proto_base_expr'
: is not a member of 'smart::smartint'
Pointing here:
-----------------
template<typename Expr, typename Grammar>
struct matches
: detail::matches_<
typename Expr::proto_base_expr
, typename Grammar::proto_base_expr
>
{};
-----------------
So apparently, while callable_context is trying to find an appropriate
overload for some stuff, it tries out my template operator, passing a
smartint as Expr, and matches<> can't handle adapted types. Because the
error is within matches<>, it's not SFINAEable and the compiler errors out
instead of eliminating the function.
What can I do? Can I teach matches<> to handle adapted types? Is there a
"right" way to implement smartint so that it needn't be an adapted type,
which would work around the whole issue? Is this a bug in Proto that is
fixed in trunk, or can be fixed?
Sebastian
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net