Re: [boost] [proto] Problems with operator <<

Folks,
I'm having no end of problems with operator<< and proto.
In the beginning, operator << was overloaded for stream output and everything worked OK, then I added the left shift operator<< to the list of protoized operators in the grammar and everything broke. The strange thing is that:
std::cout << a+b;
correctly finds my stream out overload:
template <class Exp> inline std::ostream& operator << (std::ostream& os, const big_number_exp<Exp>& r)
But
std::cout << a;
no longer calls:
template <class Backend> inline std::ostream& operator << (std::ostream& os, const big_number<Backend>& r)
But calls the proto << operator instead.
I'm at a complete loss to explain this, both of my overloads are in the same namespace as their respective types, and as far as I can see both should be preferred to the proto versions.
To answer my own question - in case anyone else gets bitten by this - the answer is you need to provide overloads with both const and non-const reference RHS arguments to effectively hide the proto operator versions. Still some hair left yours.... John.

On 8/25/2011 4:08 AM, John Maddock wrote:
To answer my own question - in case anyone else gets bitten by this - the answer is you need to provide overloads with both const and non-const reference RHS arguments to effectively hide the proto operator versions.
Still some hair left yours.... John.
Why answer you own question when I answered it for you yesterday? http://article.gmane.org/gmane.comp.lib.boost.devel/222816 And I think you have a reason to actual disable proto's operators instead of just hide them. Check the msg I sent yesterday. -- Eric Niebler BoostPro Computing http://www.boostpro.com

To answer my own question - in case anyone else gets bitten by this - the answer is you need to provide overloads with both const and non-const reference RHS arguments to effectively hide the proto operator versions.
Still some hair left yours.... John.
Why answer you own question when I answered it for you yesterday?
Strange... that was exactly the answer I needed but it didn't show up in my inbox... would have saved me some time too :-(
And I think you have a reason to actual disable proto's operators instead of just hide them. Check the msg I sent yesterday.
The thing is I need left and right shift to be protoized, but I also need to be able to overload for stream out, I ended up with several overloads looking like: template <class Stream, class Backend> typename enable_if<is_convertible<Stream*, std::ostream*>, std::ostream&>::type operator << (Stream& os, big_number<Backend>& r) Which did the trick, and preserve protos shift operators, while still working with all stream types. BTW I do specify a proto grammar, and only enable the operators I need on a case by case basis, in this case though I would need to restrict the grammar so that proto's shift operators are only enabled for RHS arguments of integer type. Is that possible? John.

On 8/25/2011 11:57 AM, John Maddock wrote:
BTW I do specify a proto grammar, and only enable the operators I need on a case by case basis, in this case though I would need to restrict the grammar so that proto's shift operators are only enabled for RHS arguments of integer type. Is that possible?
Yes. Can you post your grammar? -- Eric Niebler BoostPro Computing http://www.boostpro.com

BTW I do specify a proto grammar, and only enable the operators I need on a case by case basis, in this case though I would need to restrict the grammar so that proto's shift operators are only enabled for RHS arguments of integer type. Is that possible?
Yes. Can you post your grammar?
Pretty basic at present, need to refine those terminals a bit more! : struct big_number_grammar : proto::or_< proto::terminal< proto::_ > , proto::plus< big_number_grammar, big_number_grammar > , proto::multiplies< big_number_grammar, big_number_grammar > , proto::minus< big_number_grammar, big_number_grammar > , proto::divides< big_number_grammar, big_number_grammar > , proto::unary_plus< big_number_grammar > , proto::negate< big_number_grammar > , proto::modulus<big_number_grammar, big_number_grammar> , proto::shift_left<big_number_grammar, big_number_grammar> , proto::shift_right<big_number_grammar, big_number_grammar> > {}; I assume I could replace , proto::shift_right<big_number_grammar, big_number_grammar> with something like: , proto::shift_right<big_number_grammar, integer_terminal> Where integer_terminal is a big list of terminal integer types, but is there any way to use a predicate to say "any type that matches predicate X is a terminal"? Thanks, John.

On 8/26/2011 3:32 AM, John Maddock wrote:
BTW I do specify a proto grammar, and only enable the operators I need on a case by case basis, in this case though I would need to restrict the grammar so that proto's shift operators are only enabled for RHS arguments of integer type. Is that possible?
Yes. Can you post your grammar?
Pretty basic at present, need to refine those terminals a bit more! :
Yes!
struct big_number_grammar : proto::or_< proto::terminal< proto::_ >
You correctly identified your problem with the stream operators. std::cout matches because of the above line, and it shouldn't.
, proto::plus< big_number_grammar, big_number_grammar > , proto::multiplies< big_number_grammar, big_number_grammar > , proto::minus< big_number_grammar, big_number_grammar > , proto::divides< big_number_grammar, big_number_grammar > , proto::unary_plus< big_number_grammar > , proto::negate< big_number_grammar > , proto::modulus<big_number_grammar, big_number_grammar> , proto::shift_left<big_number_grammar, big_number_grammar> , proto::shift_right<big_number_grammar, big_number_grammar>
{};
I assume I could replace
, proto::shift_right<big_number_grammar, big_number_grammar>
with something like:
, proto::shift_right<big_number_grammar, integer_terminal>
Where integer_terminal is a big list of terminal integer types, but is there any way to use a predicate to say "any type that matches predicate X is a terminal"?
Yes. You want: // Match any integral terminal proto::and_< proto::terminal< proto::_ >, proto::if_ < boost::is_integral< proto::_value >() >
HTH, -- Eric Niebler BoostPro Computing http://www.boostpro.com

Yes. You want:
// Match any integral terminal proto::and_< proto::terminal< proto::_ >, proto::if_ < boost::is_integral< proto::_value >() >
That works a treat, thanks! Now I have another question about refining those terminals, when I have: struct big_number_grammar : proto::or_< proto::terminal<proto::_> , proto::plus< big_number_grammar, big_number_grammar > , proto::multiplies< big_number_grammar, big_number_grammar > , proto::minus< big_number_grammar, big_number_grammar > , proto::divides< big_number_grammar, big_number_grammar > , proto::unary_plus< big_number_grammar > , proto::negate< big_number_grammar > , proto::or_< proto::modulus<big_number_grammar, big_number_grammar> , proto::shift_left<big_number_grammar, integer_terminal> , proto::shift_right<big_number_grammar, integer_terminal> , proto::bitwise_and<big_number_grammar, big_number_grammar> > > {}; Then the operator overloads work just fine, but if I try and refine it to: struct big_number_grammar : proto::or_< proto::terminal<boost::math::big_number<proto::_> > , proto::plus< big_number_grammar, big_number_grammar > , proto::multiplies< big_number_grammar, big_number_grammar > , proto::minus< big_number_grammar, big_number_grammar > , proto::divides< big_number_grammar, big_number_grammar > , proto::unary_plus< big_number_grammar > , proto::negate< big_number_grammar > , proto::or_< proto::modulus<big_number_grammar, big_number_grammar> , proto::shift_left<big_number_grammar, integer_terminal> , proto::shift_right<big_number_grammar, integer_terminal> , proto::bitwise_and<big_number_grammar, big_number_grammar> > > {}; Then trying to add two big_number's results in: 1>m:\data\boost\sandbox\big_number\libs\math\ide\extended_real\scrap\scrap.cpp(24): error C2893: Failed to specialize function template 'const boost::proto::detail::enable_binary<boost::proto::domainns_::deduce_domain,boost::proto::detail::not_a_grammar,boost::mpl::or_<boost::proto::is_extension<T>,boost::proto::is_extension<Right>>,boost::proto::tag::plus,const Left,const Right>::type boost::proto::exprns_::operator +(const Left &,const Right &)' With the following template arguments: 'boost::math::mpf_real_50' 'boost::math::mpf_real_50' Where mpf_real_50 is just a typedef for "big_number<some_backend_type>". Is there anything obvious I'm doing wrong here? I'm using VC10 BTW, and big_number inherits from proto::terminal<big_number*> in case that makes any difference. Thanks again, John.

On 8/26/2011 12:53 PM, John Maddock wrote:
Yes. You want:
// Match any integral terminal proto::and_< proto::terminal< proto::_ >, proto::if_ < boost::is_integral< proto::_value >() >
That works a treat, thanks!
Now I have another question about refining those terminals, when I have:
struct big_number_grammar : proto::or_< proto::terminal<proto::_> , proto::plus< big_number_grammar, big_number_grammar > , proto::multiplies< big_number_grammar, big_number_grammar > , proto::minus< big_number_grammar, big_number_grammar > , proto::divides< big_number_grammar, big_number_grammar > , proto::unary_plus< big_number_grammar > , proto::negate< big_number_grammar > , proto::or_< proto::modulus<big_number_grammar, big_number_grammar> , proto::shift_left<big_number_grammar, integer_terminal> , proto::shift_right<big_number_grammar, integer_terminal> , proto::bitwise_and<big_number_grammar, big_number_grammar> >
{};
Then the operator overloads work just fine, but if I try and refine it to:
struct big_number_grammar : proto::or_< proto::terminal<boost::math::big_number<proto::_> > , proto::plus< big_number_grammar, big_number_grammar > , proto::multiplies< big_number_grammar, big_number_grammar > , proto::minus< big_number_grammar, big_number_grammar > , proto::divides< big_number_grammar, big_number_grammar > , proto::unary_plus< big_number_grammar > , proto::negate< big_number_grammar > , proto::or_< proto::modulus<big_number_grammar, big_number_grammar> , proto::shift_left<big_number_grammar, integer_terminal> , proto::shift_right<big_number_grammar, integer_terminal> , proto::bitwise_and<big_number_grammar, big_number_grammar> >
{};
Then trying to add two big_number's results in:
1>m:\data\boost\sandbox\big_number\libs\math\ide\extended_real\scrap\scrap.cpp(24): error C2893: Failed to specialize function template 'const boost::proto::detail::enable_binary<boost::proto::domainns_::deduce_domain,boost::proto::detail::not_a_grammar,boost::mpl::or_<boost::proto::is_extension<T>,boost::proto::is_extension<Right>>,boost::proto::tag::plus,const Left,const Right>::type boost::proto::exprns_::operator +(const Left &,const Right &)' With the following template arguments: 'boost::math::mpf_real_50' 'boost::math::mpf_real_50'
Where mpf_real_50 is just a typedef for "big_number<some_backend_type>".
Is there anything obvious I'm doing wrong here? I'm using VC10 BTW, and big_number inherits from proto::terminal<big_number*> in case that makes any difference.
That last bit does make a difference. Proto grammar matching keys off the underlying proto expression type. So change this: proto::terminal<boost::math::big_number<proto::_> > to this: proto::terminal<big_number*> (Not sure exactly what you mean by "big_number inherits from proto::terminal<big_number*>. You clearly don't mean that. You mean either i/ big_number extends proto::terminal<big_number*>::type or ii/ big_number inherits from proto::terminal<big_number*>::type. Either way, the answer is the same.) -- Eric Niebler BoostPro Computing http://www.boostpro.com

Is there anything obvious I'm doing wrong here? I'm using VC10 BTW, and big_number inherits from proto::terminal<big_number*> in case that makes any difference.
That last bit does make a difference. Proto grammar matching keys off the underlying proto expression type. So change this:
proto::terminal<boost::math::big_number<proto::_> >
to this:
proto::terminal<big_number*>
I assume you mean proto::terminal<big_number<proto::_>*> but I still get get the same error messages (the same with all the variations of the above I tried).
(Not sure exactly what you mean by "big_number inherits from proto::terminal<big_number*>. You clearly don't mean that. You mean either i/ big_number extends proto::terminal<big_number*>::type or ii/ big_number inherits from proto::terminal<big_number*>::type. Either way, the answer is the same.)
Ah yes, I meant proto::terminal<big_number<arg>*>::type. Also changed the grammar to use the proto::switch_, and yes that is better, well a bit anyway ;-) Thanks, John.

On 8/26/2011 2:08 PM, John Maddock wrote:
Is there anything obvious I'm doing wrong here? I'm using VC10 BTW, and big_number inherits from proto::terminal<big_number*> in case that makes any difference.
That last bit does make a difference. Proto grammar matching keys off the underlying proto expression type. So change this:
proto::terminal<boost::math::big_number<proto::_> >
to this:
proto::terminal<big_number*>
I assume you mean
proto::terminal<big_number<proto::_>*>
but I still get get the same error messages (the same with all the variations of the above I tried).
There's a confusion here. I was basing my suggestion on your statement: "big_number inherits from proto::terminal<big_number*>" But you misspoke, so my suggestion was wrong.
(Not sure exactly what you mean by "big_number inherits from proto::terminal<big_number*>. You clearly don't mean that. You mean either i/ big_number extends proto::terminal<big_number*>::type or ii/ big_number inherits from proto::terminal<big_number*>::type. Either way, the answer is the same.)
Ah yes, I meant proto::terminal<big_number<arg>*>::type.
Ah.
Also changed the grammar to use the proto::switch_, and yes that is better, well a bit anyway ;-)
The following is not a valid Proto grammar: proto::terminal<big_number<proto::_>*> At least, it won't match what you think it matches. Proto grammars are fairly limited in what pattern matching they do. You can see the horrible details at: http://www.boost.org/doc/libs/1_47_0/doc/html/boost/proto/matches.html Of relevance here is is the part that describes /lambda-matches/, which describes how terminals are matched. The pattern matching recurses into templates, but it doesn't peel off pointers and references and such (although it could). In this case, I would define a separate is_big_number trait like: template<typename T> struct is_big_number_ptr : mpl::false_ {}; template<typename Arg> struct is_big_number_ptr<big_number<Arg>*> : mpl::true_ {}; and use the trick with proto::and_ and proto::if_ that I gave you before. HTH, -- Eric Niebler BoostPro Computing http://www.boostpro.com

In this case, I would define a separate is_big_number trait like:
template<typename T> struct is_big_number_ptr : mpl::false_ {};
template<typename Arg> struct is_big_number_ptr<big_number<Arg>*> : mpl::true_ {};
and use the trick with proto::and_ and proto::if_ that I gave you before.
Thanks, that gets it! John.

On 8/26/2011 12:53 PM, John Maddock wrote:
struct big_number_grammar : proto::or_< proto::terminal<proto::_> , proto::plus< big_number_grammar, big_number_grammar > , proto::multiplies< big_number_grammar, big_number_grammar > , proto::minus< big_number_grammar, big_number_grammar > , proto::divides< big_number_grammar, big_number_grammar > , proto::unary_plus< big_number_grammar > , proto::negate< big_number_grammar > , proto::or_< proto::modulus<big_number_grammar, big_number_grammar> , proto::shift_left<big_number_grammar, integer_terminal> , proto::shift_right<big_number_grammar, integer_terminal> , proto::bitwise_and<big_number_grammar, big_number_grammar> >
{};
BTW, this grammar begs to be optimized with proto::switch_. Aside from that, if you're using the latest released Proto, proto::or_ can have up to 10 alternates before you need to cascade them. But use switch_. It'll compile faster. -- Eric Niebler BoostPro Computing http://www.boostpro.com
participants (2)
-
Eric Niebler
-
John Maddock