Boost logo

Boost :

From: Bo Persson (bop_at_[hidden])
Date: 2006-07-15 09:09:15


"Sean Parent" <sparent_at_[hidden]> skrev i meddelandet
news:F32736FB-26E4-47A9-AF69-15CFCA587599_at_adobe.com...
> -----
>> > Christoph Ludwig posted the correct reason why std::complex
>> > should
>> > not have an operator < () defined - sorry, my follow up using
>> > addition was poorly constructed.
>> >
>> > What I am proposing is that std::less should be defined for
>> > std::complex.
>>
>> Disagree. That could potentially break other template programming
>> using std::less, to support std::unary_negate etc. Suddenly this
>> would
>> "work" for std::complex, when it shouldn't.
> Allowing code which otherwise would not be allowed is hardly
> breaking
> anything.

It could, by allowing a change from

typedef float value_t;

to

typedef std::complex<float> value_t;

I would expect a failure for the later, and would be very surprised if
it compiled.

Also, if the code is using SFINAE to select overloads, there could be
additional surprises.

> I can see the argument that std::less<> should also be
> consistent with other operators. I think it is then important to
> define a general total order operation for this case and develop the
> rules.
> Please propose a set of rules for when operator<() should and
> should not be defined.

It should be defined when there is a general agreement on what it
means. :-)

In this specific case: If we agree that std::complex is a model of the
math concept of complex numbers, we should not define operators that
are not defined by the mathematicians.

In other cases, there can be more than one natural order and it is not
at all clear which one to choose.

An example:

struct person
{
   string first_name;
   string last_name;
   string street_address;
   string zip_code;
   string city;
   string country;
};

If I am printing address labels, the *application specific* sort order
is zip_code, but I wouldn't really want operator< to sort on zip_code,
would I. I definitely wouldn't want to sort on first_name either.

In another application, the natural sort order could be last_name, or
city, or country. Which one should we choose for the default
operator<?

Another example:

struct person2
{
    string last_name;
    string first_name;
};

Should the language standard specify that person2 is ordered on
last_name, but the person struct above ordered on first_name?
Definitely not!

>> > Why would we have a separate default relation for set/map then
>> > std::less? std::less is intended to map to operator <() on the
>> > type
>> > _or_ to a total ordering for the type if operator <() is not
>> > defined.
>>
>> No, that's just for pointers. 20.5.7/8 says:
>>
>> "For templates greater, less, greater_equal, and less_equal, the
>> specializations for any pointer type yield a total
>> order, even if the built-in operators <, >, <=, >= do not."
>>
>> It doesn't mention std::complex or any other composite types.
> That still doesn't answer the question of why have another relation
> for set/map then std::less? And as for the intent for STL I can
> assure you that the intent of the designer was std::less was
> intended
> to provide a total ordering on all types.

That might be so, but it's not how I understood it from the actual
writing in the standard document. I always got the impression that
std::less etc was a way to enable use of operators in template code.
Unlike Ada generics, which use the actual operator strings, C++ syntax
doesn't allow this, so an indirection was added.

It doesn't say that we were supposed to add an order for unordered
types. Pointers is an exception, but I see that as a late hack, not
the general rule.

>That standard also does not
> prohibit us from specializing std::less for use defined types.

True, but there is no requirement. Especially not where there is not
one single obvious order.

>> > For pair<shared_ptr<>, int> - what makes shared_ptr special?
>>
>> The fact that it is a pointer? I don't care much if it doesn't have
>> an
>> ordering.
> Then it shouldn't be different from T*.
>> >
>> > std::less is supposed to be operator <, unless operator < is not
>> > defined in which case std::less provides a total ordering. It
>> > isn't
>> > ambiguous.
>>
>> Where does the standard say that?
> I have the advantage of having Alex Stepanov on my team. I asked
> him.

Too bad then, that the intention isn't obvious from the standard text.

>> If you want to have an ordered collection of otherwise unordered
>> data,
>> the relation must be an application specific attribute. So define
>> an
>> appropriate functor, and use that with std::map, etc.
> If we want to introduce a third (or more) way to define a standard
> ordering other than operator <, std::less I'm fine with that. Just
> specify the semantics of them.

I don't want to define a standard ordering for types that doesn't
obviously have one. If I want to put my person records in sets, or
sort them, I would define an application specific order for each
particular case.

std::set<person, order_by_name> map1;
std::set<person, order_by_zip> map2;

std::sort(people, order_by_shoe_size());

Bo Persson


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk