Boost logo

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