This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: rel_ops issues


On Wed, Mar 28, 2001 at 01:24:14PM -0800, Joe Buck wrote:
> I've seen Nathan's answer on the FAQ.  I think that it is not correct,
> and that libstdc++-v3 needs more work to be a usable library.  That
> is, rel_ops is not broken, __normal_iterator needs repair.

Maybe rel_ops (in the standard) is broken _and_ __normal_iterator 
needs repair.
 
> I think that the fundamental quote
> 
>  * Short summary:  the rel_ops operators cannot be made to play nice.
>  * Don't use them.
> 
> is wrong.  The rel_ops operators *must* be made to play nice or the
> libstdc++-v3 project will have failed to deliver a conforming library.
> And they *can* be made to play nice.

No.  The other operators can be made to avoid conflicts with the rel_ops 
members for simple arguments.  That doesn't mean those rel_ops members 
are "playing nice", it means (as with the school bully) everybody else 
is doing their best to stay out of their way.

> The reason that it is correct to have a separate rel_ops namespace is
> to permit a programmer to design classes where == and != return something
> other than a bool (e.g. a lazy-evaluation expression library where the
> result is an expression object).  It is not a license to have the world
> break when the ordinary user who is not being tricky adds a using 
> directive.
 
The reason the rel_ops operators were sequestered as they are, as I recall,
is that the language's function template overloading rules aren't strong 
enough to tolerate them, in general.  

That is, once you expose an operator template on <T>, you have constrained 
all other operators in many more ways than the return type.  Results may
include not just compile-time-detected errors, but unreported undefined 
behavior.  

The rel_ops members would have been eliminated but for political concerns.
That would have been considered a "large change" at what was considered
a late point in standardization.  Sticking them in a namespace and out 
of trouble, instead, fooled inattentive members so that they went along 
with it.  Nonetheless, it amounted to an equally large, but ultimately 
confusing, change.  Much larger changes happened much later, for much
more frivolous reasons, so the better course would have been just to bite 
the bullet and eliminate them.  Oh well.
 
> Please understand what I'm saying: NOT that the rel_ops operators should
> be promoted to std, but rather that programs that say
> 
> using std::rel_ops::operator!=;
> 
> and also use STL classes must work.  Otherwise we have a release-critical
> bug: I have tons of C++ that works on about six different compilers that
> won't work with gcc 3.0.

Many broken programs will build on broken compilers.
 
> Currently many algorithms don't work as they should, e.g. operator== on
> vector<T> does not work unless there is an explicit operator!= for T (a
> requirement that isn't in the standard).

Agreed, that's a bug in vector<>.  This has nothing to do with rel_ops,
and everything to do with vector<T> improperly depending on expressions
on T that are not required to be defined.  The requirements on T for
such members are in 20.1.1, "EqualityComparable", and don't include
use of operator!=.
 
> First, the conflicts between the rel_ops operators and __normal_iterator can
> be fixed, by adding more specializations.  See
> 
> http://gcc.gnu.org/ml/gcc-bugs/2001-03/msg00822.html
> 
> for a suggestion on how to do this.  I have tested it and it works.

I can't seem to get through to look at that now.
 
> Second, STL algorithms that use the != operator on objects other than
> "normal iterators" should either include
> 	using std::rel_ops::operator!=;
> or
> 	using namespace std::relops;
> in the function body, so that the algorithms will work right (see bug
> c++/2406), or alternatively, all STL algorithms currently using a != b
> on objects other than iterators (where we know we have != defined)
> should replace it with !(a == b).  For example,

The latter alternative is correct.
 
> template <class _InputIter1, class _InputIter2>
> inline bool equal(_InputIter1 __first1, _InputIter1 __last1,
>                   _InputIter2 __first2) {
>   __STL_REQUIRES(_InputIter1, _InputIterator);
>   __STL_REQUIRES(_InputIter2, _InputIterator);
>   __STL_REQUIRES(typename iterator_traits<_InputIter1>::value_type,
>                  _EqualityComparable);
>   __STL_REQUIRES(typename iterator_traits<_InputIter2>::value_type,
>                  _EqualityComparable);
>   for ( ; __first1 != __last1; ++__first1, ++__first2)
>     if (!(*__first1 == *__first2))
>       return false;
>   return true;
> }
> 
> In the original we had
> 
>     if (*__first1 != *__first2)
>       return false;

I agree with this change.   I'm a little surprised to find that Matt 
didn't fix this a long time ago.

Nathan Myers
ncm at cantrip dot org


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]