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