Boost logo

Boost Users :

Subject: Re: [Boost-users] proto: analytical-only math functions
From: Eric Niebler (eric_at_[hidden])
Date: 2009-03-06 13:02:58


Hicham Mouline wrote:
> Eric Niebler wrote:
>> Hicham Mouline wrote:
>>> The complication comes in my case from the fact that the grammar is not
>>> stand alone type but an inner-type.
>>
>> Why does that make a difference?
>
> Rather I meant to say that the grammar "constdef_rhs_grammar" is an inner
> type of
>
> template<typename Expr>
> struct constant_wrapper
> {
> ...
> };
>
> And so in
> struct contants_domain
> : proto::domain< proto::pod_generator<constant_wrapper>,
> constant_wrapper<Expr>::constdef_rhs_grammar >
> {};
> obviously wouldn't work.

It wasn't the grammar parameter I was objecting to. In the code you
posted, you had a bogus generator:

struct contants_domain
   : proto::domain<
         proto::generator<contants_domain> // THIS IS WRONG
       , calculator_grammar
>
{};

Now you've changed the generator to
proto::pod_generator<constant_wrapper> which looks better. As for the
grammar parameter, just leave it unspecified. In your
constant_wrapper::operator= overload, you have a compile-time assertion
to catch invalid assignment expressions. That's sufficient.

For any particular Proto-based DSEL, there needs to be a 1-to-1-to-1
correspondence between:

1) The domain type,
2) The generator for the domain, which adds extra domain-specific
    functionality to expressions within the domain, and
3) The grammar for the domain, which is used to disable Proto's
    operator overloads that would create invalid expressions.

You seem to be creating a domain for constant expressions. Will these
constants be appearing within expressions of another domain? If so, I
suspect you'll run into trouble. I suggest you create 1 domain for your
DSEL, with 1 generator and 1 grammar.

You can actually have multiple expression wrappers within the same
domain with a cleverly defined generator. The only requirement on the
generator is that it is a polymorphic function object that accepts
expressions and returns (possibly wrapped) expressions. A grammar with
transforms fits this definition. Check out the following:

   #include <boost/proto/proto.hpp>
   namespace proto = boost::proto;
   using proto::_;

   template<class E> struct wrap1;
   template<class E> struct wrap2;

   // You can use a grammar with transforms as a generator
   struct Generator
     : proto::or_<
           proto::when<
               proto::assign<_,_>
             , proto::pod_generator<wrap1>(_)
>
         , proto::otherwise<
               proto::pod_generator<wrap2>(_)
>
>
   {};

   struct Domain
     : proto::domain<Generator>
   {};

   // Note, wrap1 and wrap2 are both in the same domain
   template<class E> struct wrap1
   {
       BOOST_PROTO_EXTENDS(E, wrap1, Domain)
   };

   template<class E> struct wrap2
   {
       BOOST_PROTO_EXTENDS(E, wrap2, Domain)
   };

   typedef wrap1<proto::terminal<int>::type> I;
   typedef wrap2<proto::terminal<int>::type> J;

   I const i = {{1}};
   J const j = {{2}};

   int main()
   {
       wrap1<
           proto::assign<I const &, J const &>::type
> x = (i = j); // OK, i and j are in the same domain

       wrap2<
           proto::plus<I const &, J const &>::type
> y = (i + j); // OK, i and j are in the same domain
   }

In main(), notice that an assignment creates a wrap1 object, whereas an
addition creates a wrap2 object. Both are in the same domain. In short,
you should be able to get along with just 1 domain for your DSEL, and
it'll make things *much* simpler.

HTH,

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