Re: [Boost-users] [proto] a question on assignment operators
(Public response to Maurizio's private follow-up. Hope Maurizio doesn't mind.) Maurizio Vitale wrote:
"Eric" == Eric Niebler
writes: Eric> Maurizio Vitale wrote: >> Hi Eric, while you were on vacation I posted the following on the >> boost.users Eric> <snip>
Eric> Sorry for the delay; I missed your original message. I've Eric> followed up on the boost-users list. In short: I don't Eric> understand enough of what you're trying to do to help. Please Eric> clarify and I'll help as best I can.
Let me try to rephrase what I was trying to ask and see if I'm more successful.
The gist of the question is what happens when you have to add an operator= to a proto extended expression. You normally wouldn't because in general it doesn't make much sense to do things like:
a+b = c-d;
(although it could make sense in a DSL for linear algebra) In my case something like:
(a,b,c) = expression;
would require to do (inside my_expr::operator=): a = f (expression); b = g (expression); c = h (expression);
where f,g,h depend on the semantics. In my case they would carve a certain number of bits from expression. In a DSL dealing with tuples they would select the appropriate component from expression.
OK sure, that makes sense.
The problem I'm having is that expressions built by proto seem to be const, forcing operator= to be const (or at least that's what happens in my example).
It's true, Proto's objects have a top-level const qualification. They are, after all, rvalues (temporaries) so they should not be modified. HOWEVER, the const-ness only applies at the top-level. The const-ness of child nodes is preserved. In particular, non-const lvalue terminals are held by reference and remain non-const. Consider: typedef proto::terminal<int>::type I; I i = {42}; I & refi = proto::left(i+i); The temporary object created by i+i is const, but each i is held by non-const reference, which is what is returned by proto::left.
If that's true, then my followup question was whether it is ok to perform the assignment the way I was doing it, casting away const.
In short, it shouldn't be necessary. You're using proto::flatten and fusion::fold. Somewhere in there the constness is getting messed up. You should file a bug. Proto's fold_tree transform gets the constness correct. See the attached code which is equivalent to yours, but doesn't require any ugly const_cast's.
The other question I had was on what was the reason for explicitely disable assignment operators in grammars. This is something you do in many of your examples
I do? Which examples? I don't see it.
, but doesn't seem to make a difference in my code (e.g. having an operator= in my expression seems to stop proto from building a larger tree including the '=' anyhow, without needing to disable it explicitly)
I'm afraid you've lost me again.
The last question, which was the first, it is not very important. What I'm really interesting in is how to use proto when you need to assign to a proto expression, rather than a proto terminal.
And I hope at least that much has been cleared up.
HTH,
--
Eric Niebler
BoostPro Computing
http://www.boostpro.com
#include <iostream>
#include
{};
template<typename Expr>
struct my_expr;
struct my_domain : proto::domain
"Eric" == Eric Niebler
writes:
Eric> (Public response to Maurizio's private follow-up. Hope Eric> Maurizio doesn't mind.) Not a problem. It was private to save people's bandwidth until my revised explanation was clear enough. >> The problem I'm having is that expressions built by proto seem to >> be const, forcing operator= to be const (or at least that's what >> happens in my example). Eric> It's true, Proto's objects have a top-level const Eric> qualification. They are, after all, rvalues (temporaries) so Eric> they should not be modified. Eric> HOWEVER, the const-ness only applies at the top-level. The Eric> const-ness of child nodes is preserved. In particular, Eric> non-const lvalue terminals are held by reference and remain Eric> non-const. Consider: Ok, but that toplevel constness is what forces operator= to be const. If I understand you correctly, this is intentional and having a const operator= unavoidable. It kind looks weird. Eric> typedef proto::terminal<int>::type I; I i = {42}; I & refi = Eric> proto::left(i+i); Eric> The temporary object created by i+i is const, but each i is Eric> held by non-const reference, which is what is returned by Eric> proto::left. >> If that's true, then my followup question was whether it is ok to >> perform the assignment the way I was doing it, casting away >> const. Eric> In short, it shouldn't be necessary. You're using Eric> proto::flatten and fusion::fold. Somewhere in there the Eric> constness is getting messed up. You should file a bug. I'm afraid at this point I don't understand enough of the problem in order to file an useful report with the fusion developers. I probably wouldn't be able to produce a small fragment exposing the bug and not involving proto. I can certainly send them the code as it is, if you think it would be useful. Is the boost devel mailing list the appropriate place? Eric> Proto's fold_tree transform gets the constness correct. See Eric> the attached code which is equivalent to yours, but doesn't Eric> require any ugly const_cast's. Thanks for the code. I'll study it later. >> The other question I had was on what was the reason for >> explicitely disable assignment operators in grammars. This is >> something you do in many of your examples Eric> I do? Which examples? I don't see it. lambda.hpp: // Use a grammar to disable Proto's assignment operator overloads. mixed.cpp: // A grammar which matches all the assignment operators, vector.cpp: // A grammar which matches all the assignment operators, >> , but doesn't seem to make a difference in my code (e.g. having >> an operator= in my expression seems to stop proto from building a >> larger tree including the '=' anyhow, without needing to disable >> it explicitly) Eric> I'm afraid you've lost me again. It seems like defining an operator= on extended expressions is all you need in order to prevent proto from using its own overload. Hence I was wondering what was the reason for disabling the assignment operators in the grammar, like done in the examples mentioned above. Thanks, Maurizio
Maurizio Vitale wrote:
"Eric" == Eric Niebler
writes: >> If that's true, then my followup question was whether it is ok to >> perform the assignment the way I was doing it, casting away >> const. Eric> In short, it shouldn't be necessary. You're using Eric> proto::flatten and fusion::fold. Somewhere in there the Eric> constness is getting messed up. You should file a bug.
I'm afraid at this point I don't understand enough of the problem in order to file an useful report with the fusion developers. I probably wouldn't be able to produce a small fragment exposing the bug and not involving proto.
I can certainly send them the code as it is, if you think it would be useful. Is the boost devel mailing list the appropriate place?
It could very well be a proto bug, not a fusion one, so go ahead and file it against proto and include the code you first sent.
>> The other question I had was on what was the reason for >> explicitely disable assignment operators in grammars. This is >> something you do in many of your examples
Eric> I do? Which examples? I don't see it.
lambda.hpp: // Use a grammar to disable Proto's assignment operator overloads. mixed.cpp: // A grammar which matches all the assignment operators, vector.cpp: // A grammar which matches all the assignment operators,
Ah. See below.
>> , but doesn't seem to make a difference in my code (e.g. having >> an operator= in my expression seems to stop proto from building a >> larger tree including the '=' anyhow, without needing to disable >> it explicitly)
Eric> I'm afraid you've lost me again.
It seems like defining an operator= on extended expressions is all you need in order to prevent proto from using its own overload. Hence I was wondering what was the reason for disabling the assignment operators in the grammar, like done in the examples mentioned above.
For the DSELs defined in those examples, we wanted the assignment operators (=, +=, /=, etc.) to actually do useful work rather than build still larger expression templates. Hence, proto's ET-building overloads are disabled. If you're not using +=, /=, etc. in your DSEL you can safely ignore it (i.e., not bother disabling them via SFINAE). And for operator= (a special case because it can only be defined as a member function), defining it as you have is sufficient to hide the one proto defines. HTH, -- Eric Niebler BoostPro Computing http://www.boostpro.com
"Eric" == Eric Niebler
writes:
Eric> It could very well be a proto bug, not a fusion one, so go Eric> ahead and file it against proto and include the code you first Eric> sent. Done, ticket #3364 (title: "terminals are constant after passing through proto::flatten and fusion::fold"). Regards, Maurizio
participants (3)
-
Eric Niebler
-
Maurizio Vitale
-
Maurizio Vitale