Boost logo

Proto :

Subject: Re: [proto] [Spirit-devel] [Spirit Development] Bug in today's boost_trunk -- ambiguous operator >
From: Eric Niebler (eric_at_[hidden])
Date: 2010-12-23 22:36:56


On 12/23/2010 9:42 PM, Hartmut Kaiser wrote:
>>>> I have a fairly large program that compiled just fine on boost_trunk
>>>> version 67416, but is now broken. I traced to problem to an
>>>> ambiguous operator overload that occurs when both qi.hpp and
>>>> fusion/tuple.hpp are included.
>>>>
>>>> The following code does not compile as of today, but should compile
>>>> on version 67416.
>>>>
>>>> #include <boost/fusion/tuple.hpp> //including this file caused
>>>> ambiguity errors #include <boost/spirit/include/qi.hpp> #include
>>>> <string>
>>>>
>>>> int main()
>>>> {
>>>> static const boost::spirit::qi::rule<std::string::const_iterator> a;
>>>> static const boost::spirit::qi::rule<std::string::const_iterator> b;
>>>> boost::spirit::qi::rule<std::string::const_iterator> rule = a > b;
>>>> }
>>>>
>>>
>>> Ohh, that looks serious! The ambiguity is caused by a proto/fusion
>>> overlap.
>>> A qi::rule is both, a proto expression and a fusion sequence (as all
>>> proto expressions are proto sequences now).
>>>
>>> Proto's overload for operator>() is a valid choice for this, as is
>>> fusions
>>> operator>().
>>>
>>> I'm cc'ing Eric and Christopher, perhaps they have an idea how to
>> proceed.
>>
>> I suggest defining a Fusion trait, is_less_then_comparable, and define it
>> for the built-in Fusion sequences (tuple, vector, etc.). That can be used
>> to SFINAE out Fusion's operator<, which should not be picked up for Proto
>> expressions. Ditto for the other operations on Fusion sequences.
>>
>> I have no better ideas at the moment.
>
> Fusion already has a traits class for this, but it's not SFINAE enabled (see
> boost/fusion/sequence/comparison/detail/enable_comparison.hpp), even if it's
> in 'namespace detail'.
>
> Adding an additional template parameter to make it into a customization
> point:
>
> namespace boost { namespace fusion { namespace detail
> {
> template <typename Seq1, typename Seq2, typename Enable = void>
> struct enable_equality ...
>
> template <typename Seq1, typename Seq2, typename Enable = void>
> struct enable_comparison ...
> }}}
>
> which allows to add:
>
> namespace boost { namespace fusion { namespace detail
> {
> template <typename T1, typename T2>
> struct enable_equality<T1, T2,
> typename enable_if<mpl::or_<proto::is_expr<T1>, proto::is_expr<T2> > >::type>
> : mpl::false_
> {};
>
> template <typename T1, typename T2>
> struct enable_comparison<T1, T2,
> typename enable_if<mpl::or_<proto::is_expr<T1>, proto::is_expr<T2> > > ::type>
> : mpl::false_
> {};
> }}}
>
> I'm currently running the Fusion tests to see whether the additional
> 'typename Enable = void' break anything. But I expect everything to work -
> Yep everything is fine.
>
> Eric, would you be willing to add the specializations above to Proto's
> Fusion adaptation code?

Doable, but I would feel better if these were documented customization
points of Fusion. At least move them out of the detail namespace.

Note that if we had Concepts, the Fusion operators would be restricted
to models of IsComparable, which presumably would require that each
element of the sequence could be compared and that the result was
convertible to bool. By that definition, a Proto expression is *not* a
model of IsComparable. What you're asking me (and everyone else) to do
is to explicitly state that my type does *not* model the concept. It
might be expedient in this case, but it feel vaguely wrong to me.

I'm still curious why an operator in the Fusion namespace is even being
considered. How did boost::fusion become an associated namespace of
spirit::qi::rule?

-- 
Eric Niebler
BoostPro Computing
http://www.boostpro.com

Proto list run by eric at boostpro.com