4034. Clarify specification of std::min and std::max

Section: 26.8.9 [alg.min.max] Status: New Submitter: Jan Schultke Opened: 2023-12-29 Last modified: 2024-08-02

Priority: 4

View other active issues in [alg.min.max].

View all other issues in [alg.min.max].

View all issues with New status.

Discussion:

All standard libraries effectively use the same implementation for std::min(a, b), namely something along the lines of

return __b < __a ? __b : __a;

However, the wording in 26.8.9 [alg.min.max] is not so clear:

Returns: The smaller value. Returns the first argument when the arguments are equivalent.

This leaves a few questions open:

[2024-08-02; Reflector poll]

Set priority to 4 after reflector poll. Suggestions for NAD. "The result can be determined in any way that is allowed by the constaints the function imposes on its arguments. Since the arguments must be Cpp17LessThanComparable, obviously it has to use a less-than operation, because it can't assume any other operation is possible." Some of the submitter's questions could be addressed with an editorial change.

Proposed resolution:

This wording is relative to N4971.

  1. Modify 26.8.9 [alg.min.max] as indicated:

    template<class T>
      constexpr const T& min(const T& a, const T& b);
    

    -?- Preconditions: T meets the Cpp17LessThanComparable requirements (Table 29).

    -?- Returns: b < a ? b : a.

    -?- Remarks: An invocation may explicitly specify an argument for the template parameter T.

    template<class T, class Compare>
      constexpr const T& min(const T& a, const T& b, Compare comp);
    

    -?- Returns: comp(b, a) ? b : a.

    -?- Remarks: An invocation may explicitly specify an argument for the template parameter T.

    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 = {});
    

    -1- Preconditions: For the first form, T meets the Cpp17LessThanComparable requirements (Table 29).

    -2- Returns: comp(proj(b), proj(a)) ? b : aThe smaller value. Returns the first argument when the arguments are equivalent.

    -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);
    

    -?- Preconditions: ranges::distance(r) > 0. T meets the Cpp17CopyConstructible (Table 32) and Cpp17LessThanComparable (Table 29) requirements.

    -?- Returns: The leftmost element x in r where y < x is false for all subsequent elements y.

    -?- Complexity: Exactly ranges::distance(r) - 1 comparisons.

    -?- Remarks: An invocation may explicitly specify an argument for the template parameter T.

    template<class T, class Compare>
      constexpr T min(initializer_list<T> r, Compare comp);
    

    -?- Preconditions: ranges::distance(r) > 0. T meets the Cpp17CopyConstructible requirements (Table 32).

    -?- Returns: The leftmost element x in r where comp(y, x) is false for all subsequent elements y.

    -?- Complexity: Exactly ranges::distance(r) - 1 comparisons.

    -?- Remarks: An invocation may explicitly specify an argument for the template parameter T.

    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 = {});
    

    -5- Preconditions: ranges::distance(r) > 0. For the overloads in namespace std, T meets the Cpp17CopyConstructible requirements. For the first form, T meets the Cpp17LessThanComparable requirements (Table 29).

    -6- Returns: The leftmost element x in r where comp(proj(y), proj(x)) is false for all subsequent elements yThe smallest value in the input range. Returns a copy of the leftmost element when several elements are equivalent to the smallest.

    -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);
    

    -?- Preconditions: T meets the Cpp17LessThanComparable requirements (Table 29).

    -?- Returns: a < b ? b : a.

    -?- Remarks: An invocation may explicitly specify an argument for the template parameter T.

    template<class T, class Compare>
      constexpr const T& max(const T& a, const T& b, Compare comp);
    

    -?- Returns: comp(a, b) ? b : a.

    -?- Remarks: An invocation may explicitly specify an argument for the template parameter T.

    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 = {});
    

    -9- Preconditions: For the first form, T meets the Cpp17LessThanComparable requirements (Table 29).

    -10- Returns: comp(proj(a), proj(b)) ? b : aThe larger value. Returns the first argument when the arguments are equivalent.

    -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);
    

    -?- Preconditions: ranges::distance(r) > 0. T meets the Cpp17CopyConstructible (Table 32) and Cpp17LessThanComparable (Table 29) requirements.

    -?- Returns: The leftmost element x in r where x < y is false for all subsequent elements y.

    -?- Complexity: Exactly ranges::distance(r) - 1 comparisons.

    -?- Remarks: An invocation may explicitly specify an argument for the template parameter T.

    template<class T, class Compare>
      constexpr T max(initializer_list<T> r, Compare comp);
    

    -?- Preconditions: ranges::distance(r) > 0. T meets the Cpp17CopyConstructible requirements (Table 32).

    -?- Returns: The leftmost element x in r where comp(x, y) is false for all subsequent elements y.

    -?- Complexity: Exactly ranges::distance(r) - 1 comparisons.

    -?- Remarks: An invocation may explicitly specify an argument for the template parameter T.

    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 = {});
    

    -13- Preconditions: ranges::distance(r) > 0. For the overloads in namespace std, T meets the Cpp17CopyConstructible requirements. For the first form, T meets the Cpp17LessThanComparable requirements (Table 29).

    -14- Returns: The leftmost element x in r where comp(proj(x), proj(y) is false for all subsequent elements yThe largest value in the input range. Returns a copy of the leftmost element when several elements are equivalent to the largest.

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