Boost logo

Boost Users :

Subject: Re: [Boost-users] [proto] Matching grammars in the presence of adapted types
From: Eric Niebler (eric_at_[hidden])
Date: 2010-06-04 11:16:32


On 6/4/2010 11:05 AM, Sebastian Redl wrote:
>
> 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.

It's equivalent to defining a type that has itself as a member. So yeah,
that's not going to work. What are you trying to do?

> 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
> >
> {};
>
> -----------------

Seems like a bug in Proto. Can you file a bug and attach a complete,
compilable example that demonstrates the problem?

> 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?

Well, using proto::extends is the way to go. I can help you do that,
once I figure out what you're really mean by:

  class smartint : public simd_expr<proto::terminal<smartint>::type>

Usually, you can handle this sort of thing by making a separate
smartint_impl class that has the data, and defining smartint as:

  class smartint : public simd_expr<proto::terminal<smartint_impl>::type>

Does that help?

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

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