Pete said:
"Natural" means "existing in or caused by nature; not made or caused by
humankind." Isn't numeric_limits<int>::min() made by humankind?
Well, numeric_limits<int>::min() is made by man. However, that it is the
natural / right / non-artificial <g> / ... choice for
int max_value ( int* from, int* to );
to return is not really that dependent on man. Whenever you have a partially
ordered set (such as the possible values of type int), its maximum element,
should it have one, is the right / natural / canonical / most convenient
minimum value of the empty sequence of elements. It is the only choice that
makes certain formula hold in general (i.e., without the need of treating
the empty sequence separately). To some degree, it is of course a
convention (as is any definition). However, as often in mathematics, there
are better and worse conventions. It just proves very useful to define
empty sums, products, min, max, union, and intersection accordingly so that
theorems just come out right and can be stated in full generality. That's
why it feels so natural to do that.
As for programming, I would go with the same convention because I would
expect that there are cases where the right return value will eliminate the
need for extra code handling the empty sequence case separately. Whether
that holds in a particular application, depends of course on the specs. You
are right in that regard.
However, if I had to design a _library_ version of max_value(), I would go
with the math-inspired convention. I.e., I would prefer something like
template < typename T >
struct find_min {
T const & operator() ( T const & lhs, T const & rhs ) const {
return ( std::min( lhs, rhs ) );
}
};
template < typename IntIter >
typename std::iterator_traits< IntIter >::value_type
min_value_a ( IntIter from, IntIter to ) {
typedef typename std::iterator_traits< IntIter >::value_type value_type;
return
( std::accumulate( from, to,
std::numeric_limits< value_type >::max(),
find_min<value_type>() ) );
}
to
template < typename IntIter >
typename std::iterator_traits< IntIter >::value_type
min_value_b ( IntIter from, IntIter to ) {
return ( *min_element( from, to ) );
}
An additional reason is that I tend to avoid introducing undefined behavior
in library code unless there is a clear performance rational to do so.
I agree that the version a only applies to arithmetic types. Now, I would
consider that a GoodThing(tm) since in general there might be no maximum
value for a given type, in which case min_value() does indeed not allow for
a meaningful return value when confronted with an empty sequence. In those
cases, I would recommend min_element() anyway.
Or are we both using words a bit loosely, in order to convey meaning more
clearly?
That is very likely. At least, I plead guilty to that charge. I would
contend, there is nothing wrong with that as long as one is prepared to
work things out in the case of miscommunication.
Best
Kai-Uwe Bux