<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 4034: Clarify specification of std::min and std::max</title>
<meta property="og:title" content="Issue 4034: Clarify specification of std::min and std::max">
<meta property="og:description" content="C++ library issue. Status: New">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue4034.html">
<meta property="og:type" content="website">
<meta property="og:image" content="http://cplusplus.github.io/LWG/images/cpp_logo.png">
<meta property="og:image:alt" content="C++ logo">
<style>
  p {text-align:justify}
  li {text-align:justify}
  pre code.backtick::before { content: "`" }
  pre code.backtick::after { content: "`" }
  blockquote.note
  {
    background-color:#E0E0E0;
    padding-left: 15px;
    padding-right: 15px;
    padding-top: 1px;
    padding-bottom: 1px;
  }
  ins {background-color:#A0FFA0}
  del {background-color:#FFA0A0}
  table.issues-index { border: 1px solid; border-collapse: collapse; }
  table.issues-index th { text-align: center; padding: 4px; border: 1px solid; }
  table.issues-index td { padding: 4px; border: 1px solid; }
  table.issues-index td:nth-child(1) { text-align: right; }
  table.issues-index td:nth-child(2) { text-align: left; }
  table.issues-index td:nth-child(3) { text-align: left; }
  table.issues-index td:nth-child(4) { text-align: left; }
  table.issues-index td:nth-child(5) { text-align: center; }
  table.issues-index td:nth-child(6) { text-align: center; }
  table.issues-index td:nth-child(7) { text-align: left; }
  table.issues-index td:nth-child(5) span.no-pr { color: red; }
  @media (prefers-color-scheme: dark) {
     html {
        color: #ddd;
        background-color: black;
     }
     ins {
        background-color: #225522
     }
     del {
        background-color: #662222
     }
     a {
        color: #6af
     }
     a:visited {
        color: #6af
     }
     blockquote.note
     {
        background-color: rgba(255, 255, 255, .10)
     }
  }
</style>
</head>
<body>
<hr>
<p><em>This page is a snapshot from the LWG issues list, see the <a href="lwg-active.html">Library Active Issues List</a> for more information and the meaning of <a href="lwg-active.html#New">New</a> status.</em></p>
<h3 id="4034"><a href="lwg-active.html#4034">4034</a>. Clarify specification of <code>std::min</code> and <code>std::max</code></h3>
<p><b>Section:</b> 26.8.9 <a href="https://wg21.link/alg.min.max">[alg.min.max]</a> <b>Status:</b> <a href="lwg-active.html#New">New</a>
 <b>Submitter:</b> Jan Schultke <b>Opened:</b> 2023-12-29 <b>Last modified:</b> 2024-08-02</p>
<p><b>Priority: </b>4
</p>
<p><b>View other</b> <a href="lwg-index-open.html#alg.min.max">active issues</a> in [alg.min.max].</p>
<p><b>View all other</b> <a href="lwg-index.html#alg.min.max">issues</a> in [alg.min.max].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#New">New</a> status.</p>
<p><b>Discussion:</b></p>
<p>
All standard libraries effectively use the same implementation for <code>std::min(a, b)</code>, 
namely something along the lines of
</p>
<blockquote>
<pre>
return __b &lt; __a ? __b : __a;
</pre>
</blockquote>
<ul>
<li><p><a href="https://github.com/microsoft/STL/blob/a8888806c6960f1687590ffd4244794c753aa819/stl/inc/utility#L100C22-L100C22">MSVC STL</a></p></li>
<li><p><a href="https://github.com/gcc-mirror/gcc/blob/748a4e9069e41bec1f27aa369c19f9756d8c1494/libstdc%2B%2B-v3/include/bits/stl_algobase.h#L237">libstdc++</a></p></li>
<li><p><a href="https://github.com/llvm/llvm-project/blob/b6daac023a72235108bddc17a5245a9371cd6147/libcxx/include/__algorithm/min.h#L36">libc++</a></p></li>
</ul>
<p>
However, the wording in 26.8.9 <a href="https://wg21.link/alg.min.max">[alg.min.max]</a> is not so clear:
</p>
<blockquote>
<p>
<i>Returns</i>: The smaller value. Returns the first argument when the arguments are equivalent.
</p>
</blockquote>
<p>
This leaves a few questions open:
</p>
<ul>
<li><p>How is the smaller value determined? Must it be through the less-than operator?</p></li>
<li><p>For <code>std::max</code>, can the "larger" value be determined through the greater-than operator or must it be through less-than?</p></li>
</ul>

<p><i>[2024-08-02; Reflector poll]</i></p>

<p>
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 <i>Cpp17LessThanComparable</i>, 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
<a href="https://github.com/cplusplus/draft/pull/6776">editorial change</a>.
</p>



<p id="res-4034"><b>Proposed resolution:</b></p>
<p>
This wording is relative to <a href="https://wg21.link/N4971" title=" Working Draft, Programming Languages — C++">N4971</a>.
</p>

<ol>

<li><p>Modify 26.8.9 <a href="https://wg21.link/alg.min.max">[alg.min.max]</a> as indicated:</p>

<blockquote>
<pre>
template&lt;class T&gt;
  constexpr const T&amp; min(const T&amp; a, const T&amp; b);
</pre>
<blockquote>
<p>
<ins>-?- <i>Preconditions</i>: <code>T</code> meets the <i>Cpp17LessThanComparable</i> requirements (Table 29).</ins>
<p/>
<ins>-?- <i>Returns</i>: <code>b &lt; a ? b : a</code>.</ins>
<p/>
<ins>-?- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code>.</ins>
</p>
</blockquote>
<pre>
template&lt;class T, class Compare&gt;
  constexpr const T&amp; min(const T&amp; a, const T&amp; b, Compare comp);
</pre>
<blockquote>
<p>
<ins>-?- <i>Returns</i>: <code>comp(b, a) ? b : a</code>.</ins>
<p/>
<ins>-?- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code>.</ins>
</p>
</blockquote>
<pre>
template&lt;class T, class Proj = identity,
         indirect_strict_weak_order&lt;projected&lt;const T*, Proj&gt;&gt; Comp = ranges::less&gt;
constexpr const T&amp; ranges::min(const T&amp; a, const T&amp; b, Comp comp = {}, Proj proj = {});
</pre>
<blockquote>
<p>
<del>-1- <i>Preconditions</i>: For the first form, <code>T</code> meets the <i>Cpp17LessThanComparable</i> requirements (Table 29).</del>
<p/>
-2- <i>Returns</i>: <ins><code>comp(proj(b), proj(a)) ? b : a</code></ins><del>The smaller value. Returns the first 
argument when the arguments are equivalent</del>.
<p/>
<del>-3- <i>Complexity</i>: Exactly one comparison and two applications of the projection, if any.</del>
<p/>
<del>-4- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code> of the
overloads in namespace <code>std</code>.</del>
</p>
</blockquote>
<pre>
template&lt;class T&gt;
  constexpr T min(initializer_list&lt;T&gt; r);
</pre>
<blockquote>
<p>
<ins>-?- <i>Preconditions</i>: <code>ranges::distance(r) &gt; 0</code>. <code>T</code> meets the <i>Cpp17CopyConstructible</i> 
(Table 32) and <i>Cpp17LessThanComparable</i> (Table 29) requirements.</ins>
<p/>
<ins>-?- <i>Returns</i>: The leftmost element <code>x</code> in <code>r</code> where <code>y &lt; x</code> is <code>false</code> 
for all subsequent elements <code>y</code>.</ins>
<p/>
<ins>-?- <i>Complexity</i>: Exactly <code>ranges::distance(r) - 1</code> comparisons.</ins>
<p/>
<ins>-?- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code>.</ins>
</p>
</blockquote>
<pre>
template&lt;class T, class Compare&gt;
  constexpr T min(initializer_list&lt;T&gt; r, Compare comp);
</pre>
<blockquote>
<p>
<ins>-?- <i>Preconditions</i>: <code>ranges::distance(r) &gt; 0</code>. <code>T</code> meets the <i>Cpp17CopyConstructible</i> 
requirements (Table 32).</ins>
<p/>
<ins>-?- <i>Returns</i>: The leftmost element <code>x</code> in <code>r</code> where <code>comp(y, x)</code> is <code>false</code> 
for all subsequent elements <code>y</code>.</ins>
<p/>
<ins>-?- <i>Complexity</i>: Exactly <code>ranges::distance(r) - 1</code> comparisons.</ins>
<p/>
<ins>-?- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code>.</ins>
</p>
</blockquote>
<pre>
template&lt;copyable T, class Proj = identity,
         indirect_strict_weak_order&lt;projected&lt;const T*, Proj&gt;&gt; Comp = ranges::less&gt;
  constexpr T ranges::min(initializer_list&lt;T&gt; r, Comp comp = {}, Proj proj = {});
template&lt;input_range R, class Proj = identity,
         indirect_strict_weak_order&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Comp = ranges::less&gt;
  requires indirectly_copyable_storable&lt;iterator_t&lt;R&gt;, range_value_t&lt;R&gt;*&gt;
  constexpr range_value_t&lt;R&gt;
    ranges::min(R&amp;&amp; r, Comp comp = {}, Proj proj = {});
</pre>
<blockquote>
<p>
-5- <i>Preconditions</i>: <code>ranges::distance(r) &gt; 0</code>. <del>For the overloads in namespace <code>std</code>, 
<code>T</code> meets the <i>Cpp17CopyConstructible</i> requirements. For the first form, <code>T</code> meets the 
<i>Cpp17LessThanComparable</i> requirements (Table 29).</del>
<p/>
-6- <i>Returns</i>: <ins>The leftmost element <code>x</code> in <code>r</code> where <code>comp(proj(y), proj(x))</code> 
is <code>false</code> for all subsequent elements <code>y</code></ins><del>The smallest value in the input range. 
Returns a copy of the leftmost element when several elements are equivalent to the smallest</del>.
<p/>
-7- <i>Complexity</i>: Exactly <code>ranges::distance(r) - 1</code> comparisons and twice as many applications of the
projection<del>, if any</del>.
<p/>
<del>-8- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code> of the
overloads in namespace <code>std</code>.</del>
</p>
</blockquote>
<pre>
template&lt;class T&gt;
  constexpr const T&amp; max(const T&amp; a, const T&amp; b);
</pre>
<blockquote>
<p>
<ins>-?- <i>Preconditions</i>: <code>T</code> meets the <i>Cpp17LessThanComparable</i> requirements (Table 29).</ins>
<p/>
<ins>-?- <i>Returns</i>: <code>a &lt; b ? b : a</code>.</ins>
<p/>
<ins>-?- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code>.</ins>
</p>
</blockquote>
<pre>
template&lt;class T, class Compare&gt;
  constexpr const T&amp; max(const T&amp; a, const T&amp; b, Compare comp);
</pre>
<blockquote>
<p>
<ins>-?- <i>Returns</i>: <code>comp(a, b) ? b : a</code>.</ins>
<p/>
<ins>-?- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code>.</ins>
</p>
</blockquote>
<pre>
template&lt;class T, class Proj = identity,
         indirect_strict_weak_order&lt;projected&lt;const T*, Proj&gt;&gt; Comp = ranges::less&gt;
  constexpr const T&amp; ranges::max(const T&amp; a, const T&amp; b, Comp comp = {}, Proj proj = {});
</pre>
<blockquote>
<p>
<del>-9- <i>Preconditions</i>: For the first form, <code>T</code> meets the <i>Cpp17LessThanComparable</i> requirements (Table 29).</del>
<p/>
-10- <i>Returns</i>: <ins><code>comp(proj(a), proj(b)) ? b : a</code></ins><del>The larger value. Returns the first 
argument when the arguments are equivalent</del>.
<p/>
<del>-11- <i>Complexity</i>: Exactly one comparison and two applications of the projection, if any.</del>
<p/>
<del>-12- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code> 
of the overloads in namespace <code>std</code>.</del>
</p>
</blockquote>
<pre>
template&lt;class T&gt;
  constexpr T max(initializer_list&lt;T&gt; r);
</pre>
<blockquote>
<p>
<ins>-?- <i>Preconditions</i>: <code>ranges::distance(r) &gt; 0</code>. <code>T</code> meets the <i>Cpp17CopyConstructible</i> 
(Table 32) and <i>Cpp17LessThanComparable</i> (Table 29) requirements.</ins>
<p/>
<ins>-?- <i>Returns</i>: The leftmost element <code>x</code> in <code>r</code> where <code>x &lt; y</code> is <code>false</code> 
for all subsequent elements <code>y</code>.</ins>
<p/>
<ins>-?- <i>Complexity</i>: Exactly <code>ranges::distance(r) - 1</code> comparisons.</ins>
<p/>
<ins>-?- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code>.</ins>
</p>
</blockquote>
<pre>
template&lt;class T, class Compare&gt;
  constexpr T max(initializer_list&lt;T&gt; r, Compare comp);
</pre>
<blockquote>
<p>
<ins>-?- <i>Preconditions</i>: <code>ranges::distance(r) &gt; 0</code>. <code>T</code> meets the <i>Cpp17CopyConstructible</i> 
requirements (Table 32).</ins>
<p/>
<ins>-?- <i>Returns</i>: The leftmost element <code>x</code> in <code>r</code> where <code>comp(x, y)</code> is <code>false</code> 
for all subsequent elements <code>y</code>.</ins>
<p/>
<ins>-?- <i>Complexity</i>: Exactly <code>ranges::distance(r) - 1</code> comparisons.</ins>
<p/>
<ins>-?- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code>.</ins>
</p>
</blockquote>
<pre>
template&lt;copyable T, class Proj = identity,
         indirect_strict_weak_order&lt;projected&lt;const T*, Proj&gt;&gt; Comp = ranges::less&gt;
  constexpr T ranges::max(initializer_list&lt;T&gt; r, Comp comp = {}, Proj proj = {});
template&lt;input_range R, class Proj = identity,
         indirect_strict_weak_order&lt;projected&lt;iterator_t&lt;R&gt;, Proj&gt;&gt; Comp = ranges::less&gt;
  requires indirectly_copyable_storable&lt;iterator_t&lt;R&gt;, range_value_t&lt;R&gt;*&gt;
  constexpr range_value_t&lt;R&gt;
    ranges::max(R&amp;&amp; r, Comp comp = {}, Proj proj = {});
</pre>
<blockquote>
<p>
-13- <i>Preconditions</i>: <code>ranges::distance(r) &gt; 0</code>. <del>For the overloads in namespace <code>std</code>, 
<code>T</code> meets the <i>Cpp17CopyConstructible</i> requirements. For the first form, <code>T</code> meets the 
<i>Cpp17LessThanComparable</i> requirements (Table 29).</del>
<p/>
-14- <i>Returns</i>: <ins>The leftmost element <code>x</code> in <code>r</code> where <code>comp(proj(x), proj(y)</code> 
is <code>false</code> for all subsequent elements <code>y</code></ins><del>The largest value in the input range. 
Returns a copy of the leftmost element when several elements are equivalent to the largest</del>.
<p/>
-15- <i>Complexity</i>: Exactly <code>ranges::distance(r) - 1</code> comparisons and twice as many applications of the
projection<del>, if any</del>.
<p/>
<del>-16- <i>Remarks</i>: An invocation may explicitly specify an argument for the template parameter <code>T</code> 
of the overloads in namespace <code>std</code>.</del>
</p>
</blockquote>
</blockquote>

</li>

</ol>







</body>
</html>
