min
,
max
, and minmax
is unclearSection: 26.8.9 [alg.min.max] Status: New Submitter: Casey Carter Opened: 2024-10-20 Last modified: 2024-10-20
Priority: Not Prioritized
View other active issues in [alg.min.max].
View all other issues in [alg.min.max].
View all issues with New status.
Discussion:
Editorial issue #6747
finds it inconsistent that
the wording for the max
, min
, and minmax
algorithms
uses "larger" and "smaller"
- terms normally applied to physical quantities -
to refer to relationships between values
which we term "greater" and "lesser"
everywhere else in the Working Paper.
Using "greater" and "lesser" would make it no less (pun intended)
of a problem that we describe the ordering imposed by
an arbitrary binary predicate as if it is a less-than ordering.
For example, 26.8.9 [alg.min.max] para 2 says that
std::ranges::min(13, 42, std::greater{})
"Returns: The smaller value.
Returns the first argument when
the arguments are equivalent."
The smaller of 13 and 42 is 13, which is not what this call yields.
The reader is supposed to somehow know that "The smaller value" actually means
"the value we'd call the lesser if the arguments were numbers and
comp
described a less-then ordering."
It would be clearer and more concise to simply say
it returns b
if
invoke(comp, invoke(proj, b), invoke(proj, a))
yields true
and a
otherwise.
Proposed resolution:
This wording is relative to N4993.
Modify 26.8.9 [alg.min.max] as indicated:
template<class T> constexpr const T& min(const T& a, const T& b); template<class T, class Compare> constexpr const T& min(const T& a, const T& b, Compare comp); template<class T, class Proj = identity, indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less> constexpr const T& ranges::min(const T& a, const T& b, Comp comp = {}, Proj proj = {});
-?- Let comp
be less{}
and
proj
be identity{}
for the overloads with no parameters by those names.
-1- Preconditions:
For the first form, T
meets the
Cpp17LessThanComparable
requirements
(Table [tab:cpp17.lessthancomparable]).
-2- Returns: The smaller value.
Returns the first argument
when the arguments are equivalent.
Effects: Equivalent to:
return invoke(comp, invoke(proj, b), invoke(proj, a)) ? b : a;
-3- Complexity: Exactly one comparison
and two applications of the projection, if any.
-4- Remarks: An invocation may explicitly specify
an argument for the template parameter T
of the overloads in namespace std
.
template<class T> constexpr T min(initializer_list<T> r); template<class T, class Compare> constexpr T min(initializer_list<T> r, Compare comp); template<copyable T, class Proj = identity, indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less> constexpr T ranges::min(initializer_list<T> r, Comp comp = {}, Proj proj = {}); template<input_range R, class Proj = identity, indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less> requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*> constexpr range_value_t<R> ranges::min(R&& r, Comp comp = {}, Proj proj = {});
-?- Let comp
be less{}
and proj
be
identity{}
for the overloads with no parameters by those names.
-5- Preconditions: ranges::distance(r) > 0
.
For the overloads in namespace std
, T
meets the
Cpp17CopyConstructible
requirements
(Table [tab:cpp17.copyconstructible]).
For the first form, T
meets the
Cpp17LessThanComparable
requirements
(Table [tab:cpp17.lessthancomparable]).
-6- Returns: The smallest value in the input range.
Returns a copy of the leftmost element
when several elements are equivalent to the smallest.
Returns a copy of the leftmost element e
in the input range r
for which
bool(invoke(comp, invoke(proj, x), invoke(proj, e)))
is false
for all elements x
in r
.
-7- Complexity: Exactly ranges::distance(r) - 1
comparisons and
twice as many applications of the projection, if any.
-8- Remarks: An invocation may explicitly specify an argument
for the template parameter T
of the overloads in namespace std
.
template<class T> constexpr const T& max(const T& a, const T& b); template<class T, class Compare> constexpr const T& max(const T& a, const T& b, Compare comp); template<class T, class Proj = identity, indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less> constexpr const T& ranges::max(const T& a, const T& b, Comp comp = {}, Proj proj = {});
-?- Let comp
be less{}
and proj
be identity{}
for the overloads with no parameters by those names.
-9- Preconditions: For the first form,
T
meets the Cpp17LessThanComparable
requirements
(Table [tab:cpp17.lessthancomparable]).
-10- Returns: The larger value.
Returns the first argument when the arguments are equivalent.
Effects: Equivalent to:
return invoke(comp, invoke(proj, a), invoke(proj, b)) ? b : a;
-11- Complexity: Exactly one comparison
and two applications of the projection, if any.
-12- Remarks: An invocation may explicitly specify an argument
for the template parameter T
of the overloads in namespace std
.
template<class T> constexpr T max(initializer_list<T> r); template<class T, class Compare> constexpr T max(initializer_list<T> r, Compare comp); template<copyable T, class Proj = identity, indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less> constexpr T ranges::max(initializer_list<T> r, Comp comp = {}, Proj proj = {}); template<input_range R, class Proj = identity, indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less> requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*> constexpr range_value_t<R> ranges::max(R&& r, Comp comp = {}, Proj proj = {});
-?- Let comp
be less{}
and proj
be identity{}
for the overloads with no parameters by those names.
-13- Preconditions: ranges::distance(r) > 0
.
For the overloads in namespace std
,
T
meets the Cpp17CopyConstructible
requirements
(Table [tab:cpp17.copyconstructible]).
For the first form, T
meets
the Cpp17LessThanComparable
requirements
(Table [tab:cpp17.lessthancomparable]).
-14- Returns: The largest value in the input range.
Returns a copy of the leftmost element
when several elements are equivalent to the largest.
Returns a copy of the leftmost element e
in the input range r
for which
bool(invoke(comp, invoke(proj, e), invoke(proj, x)))
is false
for all elements x
in r
.
-15- Complexity: Exactly ranges::distance(r) - 1
comparisons
and twice as many applications of the projection, if any.
-16- Remarks: An invocation may explicitly specify an argument
for the template parameter T
of the overloads in namespace std
.
template<class T> constexpr pair<const T&, const T&> minmax(const T& a, const T& b); template<class T, class Compare> constexpr pair<const T&, const T&> minmax(const T& a, const T& b, Compare comp); template<class T, class Proj = identity, indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less> constexpr ranges::minmax_result<const T&> ranges::minmax(const T& a, const T& b, Comp comp = {}, Proj proj = {});
-?- Let comp
be less{}
and proj
be identity{}
for the overloads with no parameters by those names.
-17- Preconditions: For the first form,
T
meets the Cpp17LessThanComparable
requirements
(Table [tab:cpp17.lessthancomparable]).
-18- Returns: {b, a}
if b
is smaller than a
bool(invoke(comp, invoke(proj, b), invoke(proj, a)))
is true
,
and {a, b}
otherwise.
-19- Complexity: Exactly one comparison
and two applications of the projection, if any.
-20- Remarks: An invocation may explicitly specify an argument
for the template parameter T
of the overloads in namespace std
.
template<class T> constexpr pair<T, T> minmax(initializer_list<T> t); template<class T, class Compare> constexpr pair<T, T> minmax(initializer_list<T> t, Compare comp); template<copyable T, class Proj = identity, indirect_strict_weak_order<projected<const T*, Proj>> Comp = ranges::less> constexpr ranges::minmax_result<T> ranges::minmax(initializer_list<T> r, Comp comp = {}, Proj proj = {}); template<input_range R, class Proj = identity, indirect_strict_weak_order<projected<iterator_t<R>, Proj>> Comp = ranges::less> requires indirectly_copyable_storable<iterator_t<R>, range_value_t<R>*> constexpr ranges::minmax_result<range_value_t<R>> ranges::minmax(R&& r, Comp comp = {}, Proj proj = {});
-?- Let comp
be less{}
and proj
be identity{}
for the overloads with no parameters by those names.
-21- Preconditions: ranges::distance(r) > 0
.
For the overloads in namespace std
,
T
meets the Cpp17CopyConstructible
requirements
(Table [tab:cpp17.copyconstructible]).
For the first form, T
meets
the Cpp17LessThanComparable
requirements
(Table [tab:cpp17.lessthancomparable]).
-22- Returns: Let X
be the return type.
Returns X{x, y}
,
where x
is a copy of the leftmost element
with the smallest value
in the input range r
for which
bool(invoke(comp, invoke(proj, e), invoke(proj, x)))
is false
for all elements e
in r
,
and y
is a copy of the rightmost element
with the largest value in the input range
in r
for which
bool(invoke(comp, invoke(proj, y), invoke(proj, e)))
is false
for all elements e
in r
.
-23- Complexity: At most (3/2)ranges::distance(r)
applications of the corresponding predicatecomparisons
and twice as many applications of the projection, if any.
-24- Remarks: An invocation may explicitly specify an argument
for the template parameter T
of the overloads in namespace std
.