
Hi, I'm trying to get boost::proto to turn udt(v1,v2) into a parse tree. Up to now I haven't got past the compiler asking for an udt::operator()(int,int). I can probably define such an operator for my UDT and return a proto::expr tree, but I was hoping in proto providing overloads so that I don't have to do it for all my types. I've looked into expr.hpp and there seem to be something related to this, but I don't seem to be able to make use of it. What is the best way to achieve what I'm trying? Thanks a lot, Maurizio

Maurizio Vitale wrote:
Hi,
I'm trying to get boost::proto to turn udt(v1,v2) into a parse tree. Up to now I haven't got past the compiler asking for an udt::operator()(int,int).
I can probably define such an operator for my UDT and return a proto::expr tree, but I was hoping in proto providing overloads so that I don't have to do it for all my types.
I've looked into expr.hpp and there seem to be something related to this, but I don't seem to be able to make use of it.
What is the best way to achieve what I'm trying?
As you noticed, proto::expr<> has operator() overloads, and everything in proto is an expr<>, including terminals, so you can do this: struct udt_tag {}; proto::terminal<udt_tag>::type const udt = {{}}; And now udt(v1,v2) will build parse trees. If you want udt to have extra member functions, you would use proto::extends<>, like this: struct udt_ex : proto::extends<proto::terminal<udt_tag>::type, udt_ex> { udt_ex() {} using proto::extends<proto::terminal<udt_tag>::type, udt_ex> ::operator=; void do_stuff() {...} ... }; udt_ex const udt; HTH, -- Eric Niebler Boost Consulting www.boost-consulting.com

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. I still have a couple of issues: - although udt_ex(v) is now parsed, udt_ex(v1,v2) is not. 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. The ambiguity goes away with numbers larger than 2). (anyhow BOOST_PROTO_MAX_ARITY seems to be defined to 5 in proto_fwd.hpp) - with your suggestion, when an object of class udt_ex is encountered in an expression, the corresponding node in the parse tree has a udt_tag. 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? 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. Thanks again, Maurizio

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?
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; } 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. The ambiguity goes away
with numbers larger than 2). (anyhow BOOST_PROTO_MAX_ARITY seems to be defined to 5 in proto_fwd.hpp)
- with your suggestion, when an object of class udt_ex is encountered in an expression, the corresponding node in the parse tree has a udt_tag.
Yes.
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. 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? -- Eric Niebler Boost Consulting www.boost-consulting.com

I apologize for the long post. It is probably too long for your holidays, I can wait. Eric Niebler <eric@boost-consulting.com> 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) #define BOOST_PROTO_MAX_ARITY 2 #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; x(1,2); return 0; } I'm also including the error message produced by the Intel compiler, in case you didn't have it: 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 BOOST_PP_LOCAL_MACRO(2) ^ 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 x(1,2); ^
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); } private: 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 can. 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. Regards, Maurizio

Sorry for the delay. I'm back from my trip and getting caught up. Maurizio Vitale wrote:
This is a short example that shows the problem (I'm using GCC 4.1.2) (ARITY 1 fails for different reasons)
#define BOOST_PROTO_MAX_ARITY 2 #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;
x(1,2); return 0; }
Ah. There's a bug in proto/debug.hpp. It's fixed now. Thanks for the report.
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 x(1,2); ^
This is not a bug. This expression *looks* like it has arity 2, but it actually has arity 3, the three children being x, 1 and 2. By defining BOOST_PROTO_MAX_ARITY to 2, there is no operator() that accepts enough arguments. <snip>
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.
From later mails, it seems you now have this well in hand.
Thanks for all the hand-holding during my first steps with proto.
No problem. -- Eric Niebler Boost Consulting www.boost-consulting.com

Eric, I'm trying to following your suggestion of putting data inside what used to be a simple tag and then extend it. This is a simplified version of what I need, without non-default contexts and domains. The problem I'm seeng seems to have to do with display_expr (e.g. the naked expressions alone seems to compile, although I'm not sure how smart the compiler is allowed to do when values are unused and everything is visible within the same file). display_expr is very nice to have, and I think will be even more useful when I'll start with transformations. There're other behaviours of it that looks strange to me, I'll try to reduce them to small examples asap. I see that in debug.hpp you handle the case of 1 and 2 arguments explicitely and then the general case of 3 <= N <= BOOST_PROTO_MAX_ARITY using the boost preprocessor. It seems to me that all cases could be handled uniformly (I'm not sure about the case for N=1, where you use display(proto::arg(expr)): is arg equivalent to arg_c<0>)? This part of debug.hpp seems also the likely cause of the problem I've mentioned in my other post (ambiguity when BOOST_PROTO_MAX_ARITY==2). It might be that the preprocessor iterates at least once anyhow, which might give a double definition for the case N==2 (why the generated item would correspond to the end of iteration rather than the beginning I don't know). It might be a bug in the preprocessor, but I don't know enough about what it is supposed to do. I also don't know why the case N==2 and N==3 below fail, as N==2 is handled as special case, (like N==1, which is ok) while N==3 is handled by preprocessor expansion of different code (like N==4, which is ok). #include <iostream> #include <boost/xpressive/proto/proto.hpp> #include <boost/xpressive/proto/context.hpp> #include <boost/xpressive/proto/extends.hpp> #include <boost/xpressive/proto/debug.hpp> #include <boost/typeof/typeof.hpp> #include <boost/typeof/std/ostream.hpp> namespace proto=boost::proto; struct udt_tag { friend std::ostream& operator << (std::ostream& os, const udt_tag o); unsigned int m_data; }; std::ostream& operator << (std::ostream& os, const udt_tag o) { os << "~" << o.m_data << "~"; return os; } struct udt_ex : proto::extends<proto::terminal<udt_tag>::type, udt_ex> { typedef proto::extends<proto::terminal<udt_tag>::type, udt_ex> expr_type; udt_ex () {} udt_ex (int i) : expr_type (expr_type::type::make (i)) {} using proto::extends<proto::terminal<udt_tag>::type, udt_ex>::operator=; }; int main (int, char**) { udt_ex b(3); display_expr (b*b(3,4,5,6)); // OK // display_expr (b*b(4,5,6)); // NOK: in proto/ref.hpp:72,73 forming reference to void // display_expr (b*b(5,6)); // NOK: in proto/ref.hpp:72,73 forming reference to void display_expr (b*b(6)); // OK b*b(3,4,5,6); // OK b*b(4,5,6); // OK b*b(5,6); // OK b*b(6); // OK }
participants (3)
-
Eric Niebler
-
Maurizio Vitale
-
Maurizio Vitale