Boost logo

Boost :

From: Maurizio Vitale (maurizio.vitale_at_[hidden])
Date: 2007-04-11 10:18:42

I apologize for the long post. It is probably too long for your holidays, I can wait.

Eric Niebler <eric_at_[hidden]> writes:

> Maurizio Vitale wrote:
> > thanks, it sure helped a lot.
> >
> > In my case I had to wrap proto::terminal inside a my_domain<>
> > wrapper. This was required
> > with the simplified code I posted, but I'm mentioning it for the
> > benefit of others trying to learn proto.
> Do you mean to say this was *not* required with the simple code you posted?

Indeed. I left the 'not' out, which unsurprisingly made my sentence meaningless.

> >
> > I still have a couple of issues:
> > - although udt_ex(v) is now parsed, udt_ex(v1,v2) is not.
> The following program compiles for me. I suspect the problem you're
> seeing is not in proto.
> #include <boost/xpressive/proto/proto.hpp>
> struct udt_tag {};
> boost::proto::terminal<udt_tag>::type const udt = {{}};
> int main() {
> udt(1,2);
> return 0;
> }

Not surprisingly your code compiles. A bit more surprisingly, mine now compiles as well.
Here's what was happening: in my udt_ex I had a data member, and a constructor
for initializing it. Hence no default constructor was generated.
Adding a default constructor fixes this particular problem, but I understand from
the rest of the mail that the place where I have my data is wrng to begin with.
> I've tried
> > to #define BOOST_PROTO_MAX_ARITY
> > to be 2, but this also doesn't seem to work (and if
> > debug.hpp is included you get an ambiguous overload
> > between debug.hpp:122 and rlocal.hpp:775.
> I don't know what rlocal.hpp is. It is not a proto header. I suspect
> some other code you're including is interfering. I'm interested to see how.

rlocal.hpp is part of the boost preprocessor which you're using for generating
the multiple overloads, so I suspect the conflict is between the same overload
being generated more than once. I haven't investigated it further, though

This is a short example that shows the problem (I'm using GCC 4.1.2)
(ARITY 1 fails for different reasons)

#include <boost/xpressive/proto/proto.hpp>
#include <boost/xpressive/proto/debug.hpp>

struct udt_tag {};
boost::proto::terminal<udt_tag>::type const udt = {{}};

struct my_type : boost::proto::extends<boost::proto::terminal<udt_tag>::type, my_type> {
  my_type (int i) {};
  my_type () {};

int main() {
  my_type x;

  return 0;

I'm also including the error message produced by the Intel compiler, in case you didn't have
cd /home/mav/dev/proto_pdl/
/opt/intel/cce/9.1.046/bin/icpc -I. -o eric{,.cpp}
./boost/preprocessor/iteration/detail/rlocal.hpp(775): error: function template "void boost::proto::op::display_expr::operator()(const boost::proto::expr<Tag, Args, 2L> &) const" has already been declared

eric.cpp(16): error: no instance of overloaded function "my_type::operator()" matches the argument list
            argument types are: (int, int)
            object type is: my_type

> > In my case udt contains additional data, not only extra
> > methods and types. What is a good way for getting
> > that information into the parse tree?
> Put the data in udt_tag. Then rename udt_tag to udt_data or some such.

I'm not sure I understand, but since you ask later for my use case I'll describe it
a bit more in detail.

I'm trying to rewrite in terms of proto a library of numeric datatypes.

The real thing will have all manners of fixed-point datatypes with limited and
unlimited prescision, signed and unsigned representations w/ different encodings
etc, but for the sake of simplicity, let's assume we have a single datatype that
wraps an unsigned integer and that the only difference from a native integer is
that we can specify a size in bit so that a limited number of bits is really used.

template<unsigned int N>
class my_int {
  my_int (unsigned int data) : m_data (data & (1U<<N - 1)) {}

  operator unsigned int () { return m_data; }
  my_int& operator= (unsigned int data) { m_data = data & (1U<<N - 1); }
  unsigned int m_data;

The goal is to be able to write:

        my_int mi,mj;
        int i;

1) mi = mi + mj*2;
2) i = mj + mi;

and delay the computation of the rhs until after optimizations have been performed.
It seems to me that 1) should be doable by having a
template<typename Expr> my_int& my_int::operator = (const Expr& e)
that does optimization and evaluation in the appropriate context (for the small
example here the default context would do).

2) seems doable by extending proto::expr in such a way that it offers an
operator int() [and all other builtin types not covered by default promotions]

Now my_int needs to be a type known to proto because it needs to be able to infect
expressions. I was doing it by extending a tag, but this alone loses the reference
to the data.

If I understand your suggestion, m_data would go inside a my_int_tag structure, so now
the parse tree contains the data and my_int would inherith from that so that its method

Wouldn't then everything that is in my_int (data, methods typedef) go into the tag and my_int
become an empty class inheriting from it (through the proto::extends mechanism which I presume
causes at some point inheritance)?

If so and the tag become a template, does proto::_ allow me to match all
proto::terminal<my_int_tag< proto::_> > ?

The lazy_vector example in the proto docs seems to do things a bit differently, but I still
have to understand it fully.

> Is specializing
> > as_expr going in the right direction?
> > Basically, I'd like something like var/val in the lambda.cpp
> > test, but without having to explicitly decorate
> > expressions.
> But you say above that you're already wrapping expressions. I'm
> confused. Maybe you could say a bit about your use case. Do you only
> want your udt terminals to have the extra data and members, or all
> expressions?

At the moment it seems that only terminals will require data members, but if the
plan I outlined above is viable, expression will need additional methods (for
converting to builtin and user-defined data types).

So the reason I'm wrapping expression is to be able to add the appropriate
conversion operators.

Thanks for all the hand-holding during my first steps with proto.

Boost list run by bdawes at, gregod at, cpdaniel at, john at