<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2464: try_emplace and insert_or_assign misspecified</title>
<meta property="og:title" content="Issue 2464: try_emplace and insert_or_assign misspecified">
<meta property="og:description" content="C++ library issue. Status: C++17">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2464.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="2464"><a href="lwg-defects.html#2464">2464</a>. <code>try_emplace</code> and <code>insert_or_assign</code> misspecified</h3>
<p><b>Section:</b> 23.4.3.4 <a href="https://wg21.link/map.modifiers">[map.modifiers]</a>, 23.5.3.4 <a href="https://wg21.link/unord.map.modifiers">[unord.map.modifiers]</a> <b>Status:</b> <a href="lwg-active.html#C++17">C++17</a>
 <b>Submitter:</b> Thomas Koeppe <b>Opened:</b> 2014-12-17 <b>Last modified:</b> 2017-07-30</p>
<p><b>Priority: </b>2
</p>
<p><b>View all other</b> <a href="lwg-index.html#map.modifiers">issues</a> in [map.modifiers].</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>
The specification of the <code>try_emplace</code> and <code>insert_or_assign</code> member functions in N4279 
contains the following errors and omissions:
</p>
<ol>
<li><p>In <code>insert_or_assign</code>, each occurrence of <code>std::forward&lt;Args&gt;(args)...</code> 
should be <code>std::forward&lt;M&gt;(obj)</code>; this is was a mistake introduced in editing.</p></li>

<li><p>In <code>try_emplace</code>, the construction of the <code>value_type</code> is misspecified, which 
is a mistake that was introduced during the evolution from a one-parameter to a variadic form. 
As written, <code>value_type(k, std::forward&lt;Args&gt;(args)...)</code> does not do the right thing; 
it can only be used with a single argument, which moreover must be convertible to a <code>mapped_type</code>. 
The intention is to allow direct-initialization from an argument pack, and the correct constructor 
should be <code>value_type(piecewise_construct, forward_as_tuple(k), 
forward_as_tuple(std::forward&lt;Args&gt;(args)...)</code>.</p></li>

<li><p> Both <code>try_emplace</code> and <code>insert_or_assign</code> are missing requirements on the 
argument types. Since the semantics of these functions are specified independent of other functions, 
they need to include their requirements.</p></li>
</ol>

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

<p>
This issue is related to <a href="lwg-defects.html#2469" title="Wrong specification of Requires clause of operator[] for map and unordered_map (Status: C++17)">2469</a><sup><a href="https://cplusplus.github.io/LWG/issue2469" title="Latest snapshot">(i)</a></sup>.
<p/>
AM: The repeated references to "first and third forms" and "second and fourth forms" is a bit cumbersome. 
Maybe split the four functions?<br/>
GR: We don't have precendent for "EmplaceConstructible from a, b, c". I don't like the ambiguity between code commas and 
text commas.<br/> 
TK: What's the danger?<br/> 
GR: It's difficult to follow standardese.<br/>
AM: It seems fine with code commas. What's the problem?<br/> 
GR: It will lead to difficulties when we use a similar construction that's not at the end of a sentence.<br/> 
AM: That's premature generalization. DK: When that happens, let's look at this again.<br/>
AM: Clean up "if the map does contain"<br/>
TK: Can we call both containers "map"? DK/GR: yes.<br/>
TK will send updated wording to DK.
<p/>
Conclusion: Update wording, then poll for tentatively ready
</p> 

<p><i>[2015-03-26, Thomas provides improved wording]</i></p>

<p>
The approach is to split the descriptions of the various blocks of four functions into two blocks each so as to make 
the wording easier to follow.
</p>

<strong>Previous resolution [SUPERSEDED]:</strong>
<blockquote class="note">
<p>This wording is relative to N4296.</p>

<ol>
<li><p>Apply the following changes to section 23.4.3.4 <a href="https://wg21.link/map.modifiers">[map.modifiers]</a> p3:</p>

<blockquote>
<pre>
template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(const key_type&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, const key_type&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: For the first and third forms, <code>value_type</code> shall be <code>EmplaceConstructible</code> into map
from <code>piecewise_construct</code>, <code>forward_as_tuple(k)</code>, <code>forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.
For the second and fourth forms, <code>value_type</code> shall be <code>EmplaceConstructible</code> into map
from <code>piecewise_construct</code>, <code>forward_as_tuple(move(k))</code>, <code>forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.</ins> 
<p/>
-3- <i>Effects</i>: <del>If the key <code>k</code> already exists in the map, there is no effect. Otherwise, inserts an element 
into the map. In the first and third forms, the element is constructed from the arguments as <code>value_type(k,
std::forward&lt;Args&gt;(args)...)</code>. In the second and fourth forms, the element is 
constructed from the arguments as <code>value_type(std::move(k), std::forward&lt;Args&gt;(args)...)</code>. 
In the first two overloads, the <code>bool</code> component of the returned pair is <code>true</code> if and only if the 
insertion took place. The returned iterator points to the element of the map whose key is equivalent to <code>k</code></del>
<ins>If the map does already contain an element whose key is equivalent to <code>k</code>, there is no effect.
Otherwise for the first and third forms inserts a <code>value_type</code> object <code>t</code> constructed with
<code>piecewise_construct</code>, <code>forward_as_tuple(k)</code>, <code>forward_as_tuple(forward&lt;Args&gt;(args)...)</code>,
for the second and fourth forms inserts a <code>value_type</code> object <code>t</code> constructed with
<code>piecewise_construct</code>, <code>forward_as_tuple(move(k))</code>, <code>forward_as_tuple(forward&lt;Args&gt;(args)...)</code></ins>.
<p/>
<ins>-?- <i>Returns</i>: In the first two overloads, the <code>bool</code> component of the returned pair is <code>true</code> 
if and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to 
<code>k</code>.</ins>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Apply the following changes to section 23.4.3.4 <a href="https://wg21.link/map.modifiers">[map.modifiers]</a> p5:</p>

<blockquote>
<pre>
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(const key_type&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, const key_type&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>is_assignable&lt;mapped_type&amp;, M&amp;&amp;>::value</code> shall be true.
For the first and third forms, <code>value_type</code> shall be <code>EmplaceConstructible</code> into map from <code>k</code>, 
<code>forward&lt;M&gt;(obj)</code>. For the second and fourth forms, <code>value_type</code> shall be <code>EmplaceConstructible</code> 
into map from <code>move(k), forward&lt;M&gt;(obj)</code>.</ins> 
<p/>
-5- <i>Effects</i>: <del>If the key <code>k</code> does not exist in the map, inserts an element into the map. In the first 
and third forms, the element is constructed from the arguments as <code>value_type(k, std::forward&lt;Args&gt;(args)...)</code>. 
In the second and fourth forms, the element is constructed from the arguments as <code>value_type(std::move(k), 
std::forward&lt;Args&gt;(args)...)</code>. If the key already exists, <code>std::forward&lt;M&gt;(obj)</code> is assigned to the
<code>mapped_type</code> corresponding to the key. In the first two overloads, the <code>bool</code> component of the returned
value is true if and only if the insertion took place. The returned iterator points to the element that
was inserted or updated</del>
<ins>If the map does already contain an element whose key is equivalent to <code>k</code>,
<code>forward&lt;M&gt;(obj)</code> is assigned to the <code>mapped_type</code> corresponding to the key.
Otherwise the first and third forms inserts a <code>value_type</code> object <code>t</code> constructed with <code>k</code>, 
<code>forward&lt;M&gt;(obj)</code>, the second and fourth forms inserts a <code>value_type</code> object <code>t</code> 
constructed with <code>move(k), forward&lt;M&gt;(obj)</code></ins>.
<p/>
<ins>-?- <i>Returns</i>: In the first two overloads, the <code>bool</code> component of the returned pair is <code>true</code> 
if and only if the insertion took place. The returned iterator points to the element of the map whose key is equivalent to 
<code>k</code>.</ins>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Apply the following changes to section 23.5.3.4 <a href="https://wg21.link/unord.map.modifiers">[unord.map.modifiers]</a> p5:</p>

<blockquote>
<pre>
template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(const key_type&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, const key_type&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: For the first and third forms, <code>value_type</code> shall be <code>EmplaceConstructible</code> into unordered_map
from <code>piecewise_construct</code>, <code>forward_as_tuple(k)</code>, <code>forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.
For the second and fourth forms, <code>value_type</code> shall be <code>EmplaceConstructible</code> into unordered_map
from <code>piecewise_construct</code>, <code>forward_as_tuple(move(k))</code>, <code>forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.</ins> 
<p/>
-5- <i>Effects</i>: <del>If the key <code>k</code> already exists in the map, there is no effect. Otherwise, inserts an element 
into the map. In the first and third forms, the element is constructed from the arguments as <code>value_type(k,
std::forward&lt;Args&gt;(args)...)</code>. In the second and fourth forms, the element is 
constructed from the arguments as <code>value_type(std::move(k), std::forward&lt;Args&gt;(args)...)</code>. 
In the first two overloads, the <code>bool</code> component of the returned pair is <code>true</code> if and only if the 
insertion took place. The returned iterator points to the element of the map whose key is equivalent to <code>k</code></del>
<ins>If the unordered_map does already contain an element whose key is equivalent to <code>k</code>, there is no effect.
Otherwise for the first and third forms inserts a <code>value_type</code> object <code>t</code> constructed with
<code>piecewise_construct</code>, <code>forward_as_tuple(k)</code>, <code>forward_as_tuple(forward&lt;Args&gt;(args)...)</code>,
for the second and fourth forms inserts a <code>value_type</code> object <code>t</code> constructed with
<code>piecewise_construct</code>, <code>forward_as_tuple(move(k))</code>, <code>forward_as_tuple(forward&lt;Args&gt;(args)...)</code></ins>.
<p/>
<ins>-?- <i>Returns</i>: In the first two overloads, the <code>bool</code> component of the returned pair is <code>true</code> 
if and only if the insertion took place. The returned iterator points to the element of the unordered_map whose key is equivalent to 
<code>k</code>.</ins>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Apply the following changes to section 23.5.3.4 <a href="https://wg21.link/unord.map.modifiers">[unord.map.modifiers]</a> p7:</p>

<blockquote>
<pre>
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(const key_type&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, const key_type&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>is_assignable&lt;mapped_type&amp;, M&amp;&amp;>::value</code> shall be true.
For the first and third forms, <code>value_type</code> shall be <code>EmplaceConstructible</code> into unordered_map from <code>k</code>, 
<code>forward&lt;M&gt;(obj)</code>. For the second and fourth forms, <code>value_type</code> shall be <code>EmplaceConstructible</code> 
into unordered_map from <code>move(k), forward&lt;M&gt;(obj)</code>.</ins> 
<p/>
-7- <i>Effects</i>: <del>If the key <code>k</code> does not exist in the map, inserts an element into the map. 
In the first and third forms, the element is constructed from the arguments as <code>value_type(k, std::forward&lt;Args&gt;(args)...)</code>. 
In the second and fourth forms, the element is constructed from the arguments as <code>value_type(std::move(k), 
std::forward&lt;Args&gt;(args)...)</code>. If the key already exists, <code>std::forward&lt;M&gt;(obj)</code> is assigned to the
<code>mapped_type</code> corresponding to the key. In the first two overloads, the <code>bool</code> component of the returned
value is true if and only if the insertion took place. The returned iterator points to the element that
was inserted or updated</del>
<ins>If the unordered_map does already contain an element whose key is equivalent to <code>k</code>,
<code>forward&lt;M&gt;(obj)</code> is assigned to the <code>mapped_type</code> corresponding to the key.
Otherwise the first and third forms inserts a <code>value_type</code> object <code>t</code> constructed with <code>k</code>, 
<code>forward&lt;M&gt;(obj)</code>, the second and fourth forms inserts a <code>value_type</code> object <code>t</code> 
constructed with <code>move(k), forward&lt;M&gt;(obj)</code></ins>.
<p/>
<ins>-?- <i>Returns</i>: In the first two overloads, the <code>bool</code> component of the returned pair is <code>true</code> 
if and only if the insertion took place. The returned iterator points to the element of the unordered_map whose key is 
equivalent to <code>k</code>.</ins>
</p>
</blockquote>
</blockquote>
</li>

</ol>
</blockquote>

<p><i>[2015-05, Lenexa]</i></p>

<p>
STL: existing wording is horrible, this is Thomas' wording and his issue<br/>
STL: already implemented the piecewise part<br/>
MC: ok with changes<br/>
STL: changes are mechanical<br/>
STL: believe this is P1, it must be fixed, we have wording<br/>
PJP: functions are sensible<br/>
STL: has been implemented<br/>
MC: consensus is to move to ready 
</p>


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

<ol>
<li><p>Apply the following changes to 23.4.3.4 <a href="https://wg21.link/map.modifiers">[map.modifiers]</a> p3+p4:</p>

<blockquote>
<pre>
template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(const key_type&amp; k, Args&amp;&amp;... args);
<del>template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);</del>
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, const key_type&amp; k, Args&amp;&amp;... args);
<del>template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);</del>
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>value_type</code> shall be <code>EmplaceConstructible</code> into <code>map</code> from 
<code>piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.</ins> 
<p/>
-3- <i>Effects</i>: <del>If the key <code>k</code> already exists in the map, there is no effect. Otherwise, inserts an element 
into the map. In the first and third forms, the element is constructed from the arguments as <code>value_type(k,
std::forward&lt;Args&gt;(args)...)</code>. In the second and fourth forms, the element is 
constructed from the arguments as <code>value_type(std::move(k), std::forward&lt;Args&gt;(args)...)</code>. 
In the first two overloads, the <code>bool</code> component of the returned pair is <code>true</code> if and only if the 
insertion took place. The returned iterator points to the element of the map whose key is equivalent to <code>k</code></del>
<ins>If the map already contains an element whose key is equivalent to <code>k</code>, there is no effect. Otherwise inserts an 
object of type <code>value_type</code> constructed with <code>piecewise_construct, forward_as_tuple(k), 
forward_as_tuple(forward&lt;Args&gt;(args)...)</code></ins>.
<p/>
<ins>-?- <i>Returns</i>: In the first overload, the <code>bool</code> component of the returned pair is <code>true</code> if and only 
if the insertion took place. The returned iterator points to the map element whose key is equivalent to <code>k</code>.</ins>
<p/>
-4- <i>Complexity</i>: The same as <code>emplace</code> and <code>emplace_hint</code>, respectively.
</p>
</blockquote>

<pre>
<ins>template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);</ins>
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>value_type</code> shall be <code>EmplaceConstructible</code> into <code>map</code> from 
<code>piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.</ins>
<p/>
<ins>-?- <i>Effects</i>: If the map already contains an element whose key is equivalent to <code>k</code>, there is no effect. 
Otherwise inserts an object of type <code>value_type</code> constructed with <code>piecewise_construct, forward_as_tuple(move(k)), 
forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.</ins>
<p/>
<ins>-?- <i>Returns</i>: In the first overload, the <code>bool</code> component of the returned pair is <code>true</code> if and only 
if the insertion took place. The returned iterator points to the map element whose key is equivalent to <code>k</code>.</ins>
<p/>
<ins>-?- <i>Complexity</i>: The same as <code>emplace</code> and <code>emplace_hint</code>, respectively.</ins>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Apply the following changes to 23.4.3.4 <a href="https://wg21.link/map.modifiers">[map.modifiers]</a> p5+p6:</p>

<blockquote>
<pre>
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(const key_type&amp; k, M&amp;&amp; obj);
<del>template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);</del>
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, const key_type&amp; k, M&amp;&amp; obj);
<del>template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);</del>
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>is_assignable&lt;mapped_type&amp;, M&amp;&amp;&gt;::value</code> shall be <code>true</code>. 
<code>value_type</code> shall be <code>EmplaceConstructible</code> into <code>map</code> from <code>k, forward&lt;M&gt;(obj)</code>.</ins> 
<p/>
-5- <i>Effects</i>: <del>If the key <code>k</code> does not exist in the map, inserts an element into the map. In the first 
and third forms, the element is constructed from the arguments as <code>value_type(k, std::forward&lt;Args&gt;(args)...)</code>. 
In the second and fourth forms, the element is constructed from the arguments as <code>value_type(std::move(k), 
std::forward&lt;Args&gt;(args)...)</code>. If the key already exists, <code>std::forward&lt;M&gt;(obj)</code> is assigned to the
<code>mapped_type</code> corresponding to the key. In the first two overloads, the <code>bool</code> component of the returned
value is true if and only if the insertion took place. The returned iterator points to the element that
was inserted or updated</del>
<ins>If the map already contains an element <code>e</code> whose key is equivalent to <code>k</code>, assigns <code>forward&lt;M&gt;(obj)</code> 
to <code>e.second</code>. Otherwise inserts an object of type <code>value_type</code> constructed with <code>k, forward&lt;M&gt;(obj)</code></ins>.
<p/>
<ins>-?- <i>Returns</i>: In the first overload, the <code>bool</code> component of the returned pair is <code>true</code> if and 
only if the insertion took place. The returned iterator points to the map element whose key is equivalent to <code>k</code>.</ins>
<p/>
-6- <i>Complexity</i>: The same as <code>emplace</code> and <code>emplace_hint</code>, respectively.
</p>
</blockquote>
<pre>
<ins>template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);</ins>
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>is_assignable&lt;mapped_type&amp;, M&amp;&amp;&gt;::value</code> shall be <code>true</code>. 
<code>value_type</code> shall be <code>EmplaceConstructible</code> into <code>map</code> from <code>move(k), forward&lt;M&gt;(obj)</code>.</ins>
<p/>
<ins>-?- <i>Effects</i>: If the map already contains an element <code>e</code> whose key is equivalent to <code>k</code>, 
assigns <code>forward&lt;M&gt;(obj)</code> to <code>e.second</code>. Otherwise inserts an object of type <code>value_type</code> 
constructed with <code>move(k), forward&lt;M&gt;(obj)</code>.</ins>
<p/>
<ins>-?- <i>Returns</i>: In the first overload, the <code>bool</code> component of the returned pair is <code>true</code> if and only 
if the insertion took place. The returned iterator points to the map element whose key is equivalent to <code>k</code>.</ins>
<p/>
<ins>-?- <i>Complexity</i>: The same as <code>emplace</code> and <code>emplace_hint</code>, respectively.</ins>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Apply the following changes to 23.5.3.4 <a href="https://wg21.link/unord.map.modifiers">[unord.map.modifiers]</a> p5+p6:</p>

<blockquote>
<pre>
template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(const key_type&amp; k, Args&amp;&amp;... args);
<del>template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);</del>
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, const key_type&amp; k, Args&amp;&amp;... args);
<del>template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);</del>
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>value_type</code> shall be <code>EmplaceConstructible</code> into <code>unordered_map</code> from 
<code>piecewise_construct, forward_as_tuple(k), forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.</ins> 
<p/>
-5- <i>Effects</i>: <del>If the key <code>k</code> already exists in the map, there is no effect. Otherwise, inserts an element 
into the map. In the first and third forms, the element is constructed from the arguments as <code>value_type(k,
std::forward&lt;Args&gt;(args)...)</code>. In the second and fourth forms, the element is 
constructed from the arguments as <code>value_type(std::move(k), std::forward&lt;Args&gt;(args)...)</code>. 
In the first two overloads, the <code>bool</code> component of the returned pair is <code>true</code> if and only if the 
insertion took place. The returned iterator points to the element of the map whose key is equivalent to <code>k</code></del>
<ins>If the map already contains an element whose key is equivalent to <code>k</code>, there is no effect. Otherwise inserts 
an object of type <code>value_type</code> constructed with <code>piecewise_construct, forward_as_tuple(k), 
forward_as_tuple(forward&lt;Args&gt;(args)...)</code></ins>.
<p/>
<ins>-?- <i>Returns</i>: In the first overload, the <code>bool</code> component of the returned pair is <code>true</code> if and only 
if the insertion took place. The returned iterator points to the map element whose key is equivalent to <code>k</code>.</ins>
<p/>
-6- <i>Complexity</i>: The same as <code>emplace</code> and <code>emplace_hint</code>, respectively.
</p>
</blockquote>
<pre>
<ins>template &lt;class... Args&gt; pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args);
template &lt;class... Args&gt; iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args);</ins>
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>value_type</code> shall be <code>EmplaceConstructible</code> into <code>unordered_map</code> from 
<code>piecewise_construct, forward_as_tuple(move(k)), forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.</ins>
<p/>
<ins>-?- <i>Effects</i>: If the map already contains an element whose key is equivalent to <code>k</code>, there is no effect. 
Otherwise inserts an object of type <code>value_type</code> constructed with <code>piecewise_construct, forward_as_tuple(move(k)), 
forward_as_tuple(forward&lt;Args&gt;(args)...)</code>.</ins>
<p/>
<ins>-?- <i>Returns</i>: In the first overload, the <code>bool</code> component of the returned pair is <code>true</code> if and only 
if the insertion took place. The returned iterator points to the map element whose key is equivalent to <code>k</code>.</ins>
<p/>
<ins>-?- <i>Complexity</i>: The same as <code>emplace</code> and <code>emplace_hint</code>, respectively.</ins>
</p>
</blockquote>
</blockquote>
</li>

<li><p>Apply the following changes to 23.5.3.4 <a href="https://wg21.link/unord.map.modifiers">[unord.map.modifiers]</a> p7+p8:</p>

<blockquote>
<pre>
template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(const key_type&amp; k, M&amp;&amp; obj);
<del>template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);</del>
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, const key_type&amp; k, M&amp;&amp; obj);
<del>template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);</del>
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>is_assignable&lt;mapped_type&amp;, M&amp;&amp;&gt;::value</code> shall be <code>true</code>. 
<code>value_type</code> shall be <code>EmplaceConstructible</code> into <code>unordered_map</code> from <code>k, 
forward&lt;M&gt;(obj)</code>.</ins> 
<p/>
-7- <i>Effects</i>: <del>If the key <code>k</code> does not exist in the map, inserts an element into the map. 
In the first and third forms, the element is constructed from the arguments as <code>value_type(k, std::forward&lt;Args&gt;(args)...)</code>. 
In the second and fourth forms, the element is constructed from the arguments as <code>value_type(std::move(k), 
std::forward&lt;Args&gt;(args)...)</code>. If the key already exists, <code>std::forward&lt;M&gt;(obj)</code> is assigned to the
<code>mapped_type</code> corresponding to the key. In the first two overloads, the <code>bool</code> component of the returned
value is true if and only if the insertion took place. The returned iterator points to the element that
was inserted or updated</del>
<ins>If the map already contains an element <code>e</code> whose key is equivalent to <code>k</code>, assigns <code>forward&lt;M&gt;(obj)</code> 
to <code>e.second</code>. Otherwise inserts an object of type <code>value_type</code> constructed with <code>k, forward&lt;M&gt;(obj)</code></ins>.
<p/>
<ins>-?- <i>Returns</i>: In the first overload, the <code>bool</code> component of the returned pair is <code>true</code> if 
and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to <code>k</code>.</ins>
<p/>
-8- <i>Complexity</i>: The same as <code>emplace</code> and <code>emplace_hint</code>, respectively.
</p>
</blockquote>
<pre>
<ins>template &lt;class M&gt; pair&lt;iterator, bool&gt; insert_or_assign(key_type&amp;&amp; k, M&amp;&amp; obj);
template &lt;class M&gt; iterator insert_or_assign(const_iterator hint, key_type&amp;&amp; k, M&amp;&amp; obj);</ins>
</pre>
<blockquote>
<p>
<ins>-?- <i>Requires</i>: <code>is_assignable&lt;mapped_type&amp;, M&amp;&amp;&gt;::value</code> shall be <code>true</code>. 
<code>value_type</code> shall be <code>EmplaceConstructible</code> into <code>unordered_map</code> from <code>move(k), 
forward&lt;M&gt;(obj)</code>.</ins>
<p/>
<ins>-?- <i>Effects</i>: If the map already contains an element <code>e</code> whose key is equivalent to <code>k</code>, 
assigns <code>forward&lt;M&gt;(obj)</code> to <code>e.second</code>. Otherwise inserts an object of type <code>value_type</code> 
constructed with <code>move(k), forward&lt;M&gt;(obj)</code>.</ins>
<p/>
<ins>-?- <i>Returns</i>:  In the first overload, the <code>bool</code> component of the returned pair is <code>true</code> if 
and only if the insertion took place. The returned iterator points to the map element whose key is equivalent to 
<code>k</code>.</ins>
<p/>
<ins>-?- <i>Complexity</i>: The same as <code>emplace</code> and <code>emplace_hint</code>, respectively.</ins>
</p>
</blockquote>
</blockquote>
</li>

</ol>





</body>
</html>
