<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2542: Missing const requirements for associative containers</title>
<meta property="og:title" content="Issue 2542: Missing const requirements for associative containers">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2542.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#C++17">C++17</a> status.</em></p>
<h3 id="2542"><a href="lwg-defects.html#2542">2542</a>. Missing <code>const</code> requirements for associative containers</h3>
<p><b>Section:</b> 23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Daniel Kr&uuml;gler <b>Opened:</b> 2015-09-26 <b>Last modified:</b> 2017-07-30</p>
<p><b>Priority: </b>1
</p>
<p><b>View other</b> <a href="lwg-index-open.html#associative.reqmts">active issues</a> in [associative.reqmts].</p>
<p><b>View all other</b> <a href="lwg-index.html#associative.reqmts">issues</a> in [associative.reqmts].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#C++17">C++17</a> status.</p>
<p><b>Discussion:</b></p>
<p>
Table 101 &mdash; "Associative container requirements" and its associated legend paragraph 
23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> p8 omits to impose constraints related to <code>const</code>
values, contrary to unordered containers as specified by Table 102 and its associated legend 
paragraph p11.
<p/>
Reading these requirements strictly, a feasible associative container could declare several
conceptual observer members &mdash; for example <code>key_comp()</code>, <code>value_comp()</code>, 
or <code>count()</code> &mdash; as non-<code>const</code> functions. In Table 102, "possibly <code>const</code>" 
values are exposed by different symbols, so the situation for unordered containers is clear
that these functions may be invoked by <code>const</code> container objects.
<p/>
For the above mentioned member functions this problem is only minor, because the synopses of the 
actual Standard associative containers do declare these members as <code>const</code> functions, but 
nonetheless a wording fix is recommended to clean up the specification asymmetry between associative 
containers and unordered containers.
<p/>
The consequences of the ignorance of <code>const</code> becomes much worse when we consider a code 
example such as the following one from a recent 
<a href="https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67617">libstdc++ bug report</a>:
</p>
<blockquote><pre>
#include &lt;set&gt;

struct compare 
{
  bool operator()(int a, int b) // Notice the <span style="color:#C80000;font-weight:bold"><em>non-<code>const</code></em></span> member declaration!
  {
    return a &lt; b;
  }
};

int main() {
  const std::set&lt;int, compare&gt; s;
  s.find(0);
}
</pre></blockquote>
<p>
The current wording in 23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> can be read to require this code to be well-formed,
because there is no requirement that an object <code>comp</code> of the ordering relation of type <code>Compare</code>
might be a <code>const</code> value when the function call expression <code>comp(k1, k2)</code> is evaluated.
<p/>
Current implementations differ: While Clangs libc++ and GCCs libstdc++ reject the above example,
the Dinkumware library associated with Visual Studio 2015 accepts it.
<p/>
I believe the current wording unintentionally misses the constraint that even <code>const</code> comparison
function objects of associative containers need to support the predicate call expression. This becomes
more obvious when considering the member <code>value_compare</code> of <code>std::map</code> which provides (only) a
<code>const operator()</code> overload which invokes the call expression of data member <code>comp</code>.
</p>

<p><i>[2016-02-20, Daniel comments and extends suggested wording]</i></p>

<p>
It has been pointed out to me, that the suggested wording is a potentially breaking change and should therefore
be mentioned in Annex C.
<p/>
First, let me emphasize that this potentially breaking change is <em>solely</em> caused by the wording change in
23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> p8:
</p>
<blockquote>
<p>
[&hellip;] and <code>c</code> denotes a <ins>possibly <code>const</code></ins> value of type <code>X::key_compare</code>; [&hellip;]
</p>
</blockquote>
<p>
So, even if that proposal would be rejected, the rest of the suggested changes could (and should) be
considered for further evaluation, because the remaining parts do just repair an obvious mismatch between
the concrete associative containers (<code>std::set</code>, <code>std::map</code>, &hellip;) and the requirement
tables.
<p/>
Second, I believe that the existing wording was never really clear in regard to <em>require</em> a Standard Library
to accept comparison functors with non-<code>const operator()</code>. If the committee really intends to require
a Library to support comparison functors with non-<code>const operator()</code>, this should be clarified by at least
an additional note to e.g. 23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> p8.
</p>

<p><i>[2016-03, Jacksonville]</i></p>

Move to Ready with Daniel's updated wording


<p id="res-2542"><b>Proposed resolution:</b></p>
<p>This wording is relative to N4567.</p>

<ol>
<li><p>Change 23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> p8 as indicated:</p>
<blockquote>
<p>
-8- In Table 101, <code>X</code> denotes an associative container class, <code>a</code> denotes a value of type 
<code>X</code>, <ins><code>b</code> denotes a possibly <code>const</code> value of type <code>X</code>,</ins> <code>u</code> denotes 
the name of a variable being declared, <code>a_uniq</code> denotes a value of 
type <code>X</code> when <code>X</code> supports unique keys, <code>a_eq</code> denotes a value of type <code>X</code> when 
<code>X</code> supports multiple keys, <code>a_tran</code> denotes a <ins>possibly <code>const</code></ins> value of type 
<code>X</code> when the <i>qualified-id</i> <code>X::key_compare::is_transparent</code> is valid and denotes a type (14.8.2), 
<code>i</code> and <code>j</code> satisfy input iterator requirements and refer to elements implicitly convertible to 
<code>value_type</code>, 
<code>[i, j)</code> denotes a valid range, <code>p</code> denotes a valid const iterator to <code>a</code>, <code>q</code> 
denotes a valid dereferenceable const iterator to <code>a</code>, <code>r</code> denotes a valid
dereferenceable iterator to <code>a</code>, <code>[q1, q2)</code> denotes a valid range of const iterators in <code>a</code>, 
<code>il</code> designates an object of type <code>initializer_list&lt;value_type&gt;</code>, <code>t</code> denotes a 
value of type <code>X::value_type</code>, <code>k</code> denotes a value of type <code>X::key_type</code> and <code>c</code> 
denotes a <ins>possibly <code>const</code></ins> value of type <code>X::key_compare</code>; <code>kl</code> is a value such that <code>a</code> is
partitioned (25.4) with respect to <code>c(r, kl)</code>, with <code>r</code> the key value of <code>e</code> and <code>e</code> 
in <code>a</code>; <code>ku</code> is a value such that <code>a</code> is partitioned with respect to <code>!c(ku, r)</code>; 
<code>ke</code> is a value such that <code>a</code> is partitioned with respect to <code>c(r, ke)</code> and <code>!c(ke, r)</code>, 
with <code>c(r, ke)</code> implying <code>!c(ke, r)</code>. <code>A</code> denotes the storage allocator used by <code>X</code>, 
if any, or <code>std::allocator&lt;X::value_type&gt;</code> otherwise, and <code>m</code> denotes an allocator of a 
type convertible to <code>A</code>.
</p>
</blockquote>
</li>

<li><p>Change 23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a>, Table 101 &mdash; "Associative container requirements" as indicated: 
<p/>
[<i>Editorial note</i>: This issue doesn't touch the note column entries for the expressions related to <code>key_comp()</code>
and <code>value_comp()</code> (except for the symbolic correction), since these are already handled by LWG issues 
<a href="lwg-active.html#2227" title="Stateful comparison objects in associative containers (Status: Open)">2227</a><sup><a href="https://cplusplus.github.io/LWG/issue2227" title="Latest snapshot">(i)</a></sup> and <a href="lwg-active.html#2215" title="(unordered) associative container functors should be CopyConstructible (Status: Open)">2215</a><sup><a href="https://cplusplus.github.io/LWG/issue2215" title="Latest snapshot">(i)</a></sup> &mdash; <i>end editorial note</i>]
</p>

<blockquote>
<table border="1">
<caption>Table 101 &mdash; Associative container requirements (in addition to container) (continued)</caption>
<tr>
<th>Expression</th>
<th>Return type</th>
<th>Assertion&#47;note pre-&#47;post-condition</th>
<th>Complexity</th>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code><del>a</del><ins>b</ins>.key_comp()</code>
</td>
<td>
<code>X::key_compare</code>
</td>
<td>
returns the comparison object<br/>
out of which <code><del>a</del><ins>b</ins></code> was<br/>
constructed.
</td>
<td>
constant
</td>
</tr>

<tr>
<td>
<code><del>a</del><ins>b</ins>.value_comp()</code>
</td>
<td>
<code>X::value_compare</code>
</td>
<td>
returns an object of<br/>
<code>value_compare</code> constructed<br/>
out of the comparison object
</td>
<td>
constant
</td>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code><del>a</del><ins>b</ins>.find(k)</code>
</td>
<td>
<code>iterator</code>;<br/>
<code>const_iterator</code> for constant <code><del>a</del><ins>b</ins></code>.
</td>
<td>
returns an iterator pointing to<br/>
an element with the key<br/>
equivalent to <code>k</code>, or <code><del>a</del><ins>b</ins>.end()</code> if<br/>
such an element is not found
</td>
<td>
logarithmic
</td>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code><del>a</del><ins>b</ins>.count(k)</code>
</td>
<td>
<code>size_type</code>
</td>
<td>
returns the number of elements<br/>
with key equivalent to <code>k</code>
</td>
<td>
<code>log(<del>a</del><ins>b</ins>.size()) + <del>a</del><ins>b</ins>.count(k)</code>
</td>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code><del>a</del><ins>b</ins>.lower_bound(k)</code>
</td>
<td>
<code>iterator</code>;<br/>
<code>const_iterator</code> for constant <code><del>a</del><ins>b</ins></code>.
</td>
<td>
returns an iterator pointing to<br/>
the first element with key not<br/>
less than <code>k</code>, or <code><del>a</del><ins>b</ins>.end()</code> if such<br/>
an element is not found.
</td>
<td>
logarithmic
</td>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code><del>a</del><ins>b</ins>.upper_bound(k)</code>
</td>
<td>
<code>iterator</code>;<br/>
<code>const_iterator</code> for constant <code><del>a</del><ins>b</ins></code>.
</td>
<td>
returns an iterator pointing to<br/>
the first element with key<br/>
greater than <code>k</code>, or <code><del>a</del><ins>b</ins>.end()</code> if<br/>
such an element is not found.
</td>
<td>
logarithmic
</td>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

<tr>
<td>
<code><del>a</del><ins>b</ins>.equal_range(k)</code>
</td>
<td>
<code>pair&lt;iterator, iterator&gt;</code>;<br/>
<code>pair&lt;const_iterator, const_iterator&gt;</code> for<br/>
constant <del>a</del><ins>b</ins>.
</td>
<td>
equivalent to <code>make_-<br/>
pair(<del>a</del><ins>b</ins>.lower_bound(k),<br/>
<del>a</del><ins>b</ins>.upper_bound(k))</code>.
</td>
<td>
logarithmic
</td>
</tr>

<tr>
<td colspan="4" align="center">
<code>&hellip;</code>
</td>
</tr>

</table>
</blockquote>

</li>

<li><p>Add a new entry to Annex C, C.4 <a href="https://wg21.link/diff.cpp14">[diff.cpp14]</a>, as indicated:</p>

<blockquote>
<p>
<ins>C.4.4 Clause 23: containers library [diff.cpp14.containers]</ins>
<p/>
<ins>23.2.4</ins>
<p/>
<ins><b>Change:</b> Requirements change: </ins>
<p/>
<ins><b>Rationale:</b> Increase portability, clarification of associative container requirements.</ins>
<p/>
<ins><b>Effect on original feature:</b> Valid 2014 code that attempts to use associative containers 
having a comparison object with non-<code>const</code> function call operator may fail to compile:</ins>
</p>
<blockquote><pre>
<ins>#include &lt;set&gt;

struct compare 
{
  bool operator()(int a, int b)
  {
    return a &lt; b;
  }
};

int main() {
  const std::set&lt;int, compare&gt; s;
  s.find(0);
}</ins>
</pre></blockquote>
</blockquote>
</li>
</ol>





</body>
</html>
