This page is a snapshot from the LWG issues list, see the Library Active Issues List for more information and the meaning of New status.

4167. Use of "smaller" and "larger" in min, max, and minmax is unclear

Section: 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.

  1. 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.