<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2059: C++0x ambiguity problem with map::erase</title>
<meta property="og:title" content="Issue 2059: C++0x ambiguity problem with map::erase">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2059.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="2059"><a href="lwg-defects.html#2059">2059</a>. C++0x ambiguity problem with <code>map::erase</code></h3>
<p><b>Section:</b> 23.4.3 <a href="https://wg21.link/map">[map]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Christopher Jefferson <b>Opened:</b> 2011-05-18 <b>Last modified:</b> 2017-07-30</p>
<p><b>Priority: </b>3
</p>
<p><b>View all other</b> <a href="lwg-index.html#map">issues</a> in [map].</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>
<code>map::erase</code> (and several related methods) took an iterator in C++03, but take a <code>const_iterator</code> 
in C++0x. This breaks code where the map's <code>key_type</code> has a constructor which accepts an iterator 
(for example a template constructor), as the compiler cannot choose between <code>erase(const key_type&amp;)</code> 
and <code>erase(const_iterator)</code>.</p>
<blockquote><pre>
#include &lt;map&gt;

struct X
{
  template&lt;typename T&gt;
  X(T&amp;) {}
};

bool operator&lt;(const X&amp;, const X&amp;) { return false; }

void erasor(std::map&lt;X,int&gt;&amp; s, X x)
{
  std::map&lt;X,int&gt;::iterator it = s.find(x);
  if (it != s.end())
    s.erase(it);
}
</pre></blockquote>

<p><i>[
2011 Bloomington
]</i></p>


<p>
This issue affects only associative container <code>erase</code> calls, and is not more general, as these are the
only functions that are also overloaded on another single arguement that might cause confusion - the <code>erase</code>
by key method.  The complete resolution should simply restore the <code>iterator</code> overload in addition to the
<code>const_iterator</code> overload for all eight associative containers. 
</p>

<p>
Proposed wording supplied by Alan Talbot, and moved to Review.
</p>


<p><i>[2012, Kona]</i></p>

<p>
Moved back to Open by post-meeting issues processing group.
</p>
<p>
Pablo very unhappy about case of breaking code with ambiguous conversion between both iterator types.
</p>
<p>
Alisdair strongly in favor of proposed resolution, this change from C++11 bit Chris in real code,
and it took a while to track down the cause.
</p>
<p>
Move to open, bring in front of a larger group
</p>
<p>
Proposed wording from Jeremiah:

<code>erase(key)</code> shall not participate in overload resolution if <code>iterator</code> is
convertible to <code>key</code>.

Note that this means making <code>erase(key)</code> a template-method
</p>
<p>
Poll Chris to find out if he already fixed his code, or fixed his library
</p>
<p>
Jeremiah - allow both overloads, but <code>enable_if</code> the <code>const_iterator</code> form as
a template, requiring <code>is_same</code> to match only <code>const_iterator</code>.
</p>
<p>
Poll PJ to see if he has already applied this fix?
</p>

<p><i>[2015-02 Cologne]</i></p>

<p>
AM: To summarize, we changed a signature and code broke. At what point do we stop and accept breakage in increasingly obscure code? 
VV: libc++ is still broken, but libstdc++ works, so they've fixed this &mdash; perhaps using this PR? [Checks] Yes, libstdc++ 
uses this solution, and has a comment pointing to LWG 2059. AM: This issue hasn't been looked at since Kona. In any case, we 
already have implementation experience now.
<p/>
AM: I'd say let's ship it. We already have implementation experience (libstdc++ and MSVS). MC: And "tentatively ready" lets me 
try to implement this and see how it works. 
</p>


<p id="res-2059"><b>Proposed resolution:</b></p>
<p>
Editorial note: The following things are different between 23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> p.8 and
23.2.8 <a href="https://wg21.link/unord.req">[unord.req]</a> p.10. These should probably be reconciled.
</p>
<blockquote>
<ol>
<li>First uses the convention "denotes";  second uses the convention "is".</li>
<li>First redundantly says: "If no such element exists, returns a.end()." in erase table entry, second does not.</li>
</ol>
</blockquote>

<p>
23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> Associative containers
</p>
<p>
8 In Table 102, <code>X</code> denotes an associative container class, <code>a</code> denotes a value of <code>X</code>, <code>a_uniq</code>
denotes a value of <code>X</code> when <code>X</code> supports unique keys, <code>a_eq</code> denotes a value of <code>X</code> when
<code>X</code> supports multiple keys, <code>u</code> denotes an identifier, <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>,
<ins><code>r</code> denotes a valid dereferenceable iterator to a,</ins> <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></code>, <code>t</code> denotes a value of
<code>X::value_type</code>, <code>k</code> denotes a value of <code>X::key_type</code> and <code>c</code> denotes a value of type
<code>X::key_compare</code>. <code>A</code> denotes the storage allocator used by <code>X</code>, if any, or
<code>std::allocator&lt;X::value_type></code> otherwise, and <code>m</code> denotes an allocator of a type convertible to <code>A</code>.
</p>

<p>
23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a> Associative containers Table 102
</p>
<p>
Add row:
</p>
<ins>
<table border="1">
<tr>
<td><code>a.erase(r)</code></td>
<td><code>iterator</code></td>
<td>
erases the element pointed to by <code>r</code>. Returns an iterator pointing to the element immediately following <code>r</code>
prior to the element being erased. If no such element exists, returns <code>a.end()</code>.
</td>
<td>amortized constant</td>
</tr>
</table>
</ins>

<p>
23.2.8 <a href="https://wg21.link/unord.req">[unord.req]</a> Unordered associative containers</p>
<p>
10 In table 103: <code>X</code> is an unordered associative container class, <code>a</code> is an object of type <code>X</code>,
<code>b</code> is a possibly const object of type <code>X</code>, <code>a_uniq</code> is an object of type <code>X</code> when
<code>X</code> supports unique keys, <code>a_eq</code> is an object of type <code>X</code> when <code>X</code> supports equivalent keys,
<code>i</code> and <code>j</code> are input iterators that refer to <code>value_type</code>, <code>[i, j)</code> is a valid range,
<code>p</code> and <code>q2</code> are valid const iterators to <code>a</code>, <code>q</code> and <code>q1</code> are valid dereferenceable
const iterators to <code>a</code>, <ins><code>r</code> is a valid dereferenceable iterator to a,</ins> <code>[q1,q2)</code> is a
valid range in <code>a</code>, <code>il</code> designates an object of type <code>initializer_list&lt;value_type></code>,
<code>t</code> is a value of type <code>X::value_type</code>, <code>k</code> is a value of type <code>key_type</code>, <code>hf</code> is a
possibly const value of type <code>hasher</code>, <code>eq</code> is a possibly const value of type <code>key_equal</code>,
<code>n</code> is a value of type <code>size_type</code>, and <code>z</code> is a value of type <code>float</code>.
</p>

<p>
23.2.8 <a href="https://wg21.link/unord.req">[unord.req]</a> Unordered associative containers Table 103
</p>
<p>
Add row:
</p>
<ins>
<table border="1">
<tr>
<td><code>a.erase(r)</code></td>
<td><code>iterator</code></td>
<td>
Erases the element pointed to by <code>r</code>. Returns the iterator immediately following <code>r</code> prior to the erasure.
</td>
<td>Average case O(1), worst case O(<code>a.size()</code>).</td>
</tr>
</table>
</ins>

<p>
23.4.3.1 <a href="https://wg21.link/map.overview">[map.overview]</a> Class template map overview p. 2
</p>
<pre>
<ins>iterator erase(iterator position);</ins>
iterator erase(const_iterator position);
size_type erase(const key_type&amp; x);
iterator erase(const_iterator first, const_iterator last);
</pre>

<p>
23.4.4.1 <a href="https://wg21.link/multimap.overview">[multimap.overview]</a> Class template multimap overview p. 2
</p>
<pre>
<ins>iterator erase(iterator position);</ins>
iterator erase(const_iterator position);
size_type erase(const key_type&amp; x);
iterator erase(const_iterator first, const_iterator last);
</pre>

<p>
23.4.6.1 <a href="https://wg21.link/set.overview">[set.overview]</a> Class template set overview p. 2
</p>
<pre>
<ins>iterator erase(iterator position);</ins>
iterator erase(const_iterator position);
size_type erase(const key_type&amp; x);
iterator erase(const_iterator first, const_iterator last);
</pre>

<p>
23.4.7.1 <a href="https://wg21.link/multiset.overview">[multiset.overview]</a> Class template multiset overview 
</p>
<pre>
<ins>iterator erase(iterator position);</ins>
iterator erase(const_iterator position);
size_type erase(const key_type&amp; x);
iterator erase(const_iterator first, const_iterator last);
</pre>

<p>
23.5.3.1 <a href="https://wg21.link/unord.map.overview">[unord.map.overview]</a> Class template unordered_map overview p. 3
</p>
<pre>
<ins>iterator erase(iterator position);</ins>
iterator erase(const_iterator position);
size_type erase(const key_type&amp; x);
iterator erase(const_iterator first, const_iterator last);
</pre>

<p>
23.5.4.1 <a href="https://wg21.link/unord.multimap.overview">[unord.multimap.overview]</a> Class template unordered_multimap overview p. 3
</p>
<pre>
<ins>iterator erase(iterator position);</ins>
iterator erase(const_iterator position);
size_type erase(const key_type&amp; x);
iterator erase(const_iterator first, const_iterator last);
</pre>

<p>
23.5.6.1 <a href="https://wg21.link/unord.set.overview">[unord.set.overview]</a> Class template unordered_set overview p. 3
</p>
<pre>
<ins>iterator erase(iterator position);</ins>
iterator erase(const_iterator position);
size_type erase(const key_type&amp; x);
iterator erase(const_iterator first, const_iterator last);
</pre>


<p>
23.5.7.1 <a href="https://wg21.link/unord.multiset.overview">[unord.multiset.overview]</a> Class template unordered_multiset overview p. 3
</p>
<pre>
<ins>iterator erase(iterator position);</ins>
iterator erase(const_iterator position);
size_type erase(const key_type&amp; x);
iterator erase(const_iterator first, const_iterator last);
</pre>

<p>
C.6.12 <a href="https://wg21.link/diff.cpp03.containers">[diff.cpp03.containers]</a> C.2.12 Clause 23: containers library 
</p>
<p>
23.2.3, 23.2.4
</p>
<p>
Change: Signature changes: from iterator to const_iterator parameters
</p>
<p>
Rationale: Overspecification. Effects: The signatures of the following member functions changed from
taking an iterator to taking a const_iterator:
</p>
<ul>
<li>insert(iter, val) for vector, deque, list, set, multiset, map, multimap</li>
<li>insert(pos, beg, end) for vector, deque, list, forward_list</li>
<li><del>erase(iter) for set, multiset, map, multimap</del></li>
<li>erase(begin, end) for set, multiset, map, multimap</li>
<li>all forms of list::splice</li>
<li>all forms of list::merge</li>
</ul>
<p>
Valid C++ 2003 code that uses these functions may fail to compile with this International Standard.
</p>





</body>
</html>
