<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 2772: Inconsistency in the insert(node) interface</title>
<meta property="og:title" content="Issue 2772: Inconsistency in the insert(node) interface">
<meta property="og:description" content="C++ library issue. Status: NAD">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue2772.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#NAD">NAD</a> status.</em></p>
<h3 id="2772"><a href="lwg-closed.html#2772">2772</a>. Inconsistency in the <code>insert(node)</code> interface</h3>
<p><b>Section:</b> 23.2.7 <a href="https://wg21.link/associative.reqmts">[associative.reqmts]</a>, 23.2.8 <a href="https://wg21.link/unord.req">[unord.req]</a>, 23.4.2 <a href="https://wg21.link/associative.map.syn">[associative.map.syn]</a>, 23.5.2 <a href="https://wg21.link/unord.map.syn">[unord.map.syn]</a> <b>Status:</b> <a href="lwg-active.html#NAD">NAD</a>
 <b>Submitter:</b> Tomasz Kami&nacute;ski <b>Opened:</b> 2016-09-06 <b>Last modified:</b> 2018-01-28</p>
<p><b>Priority: </b>2
</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#NAD">NAD</a> status.</p>
<p><b>Discussion:</b></p>
<p>
In C++17 the interface of the unique <code>map</code> was extended to include following function:
</p>
<blockquote><pre>
pair&lt;iterator, bool&gt; try_emplace(const key_type&amp; k, Args&amp;&amp;... args); //and move version
iterator try_emplace(const_iterator hint, const key_type&amp; k, Args&amp;&amp;... args); //and move version
iterator insert(const_iterator hint, node_type&amp;&amp; nh)
insert_return_type insert(node_type&amp;&amp; nh);
</pre></blockquote>
<p>
All of the functions share a common property, that they are performing basically no-operation in case when element 
with given key (part of node) is already stored in the map. However there is major difference in their interface. 
The first three functions:
</p>
<blockquote><pre>
pair&lt;iterator, bool&gt; try_emplace(key_type&amp;&amp; k, Args&amp;&amp;... args); //and copy version
iterator try_emplace(const_iterator hint, key_type&amp;&amp; k, Args&amp;&amp;... args); //and copy version
iterator insert(const_iterator hint, node_type&amp;&amp; nh)
</pre></blockquote>
<p>
are guaranteeing that the value of the arguments (<code>k, nh, args...</code>) will not be changed if the map already 
contains a key with given value, so the programmer is free to reuse it for their own purpose.
<p/>
However, the interface of the fourth function is a bit different:
</p>
<blockquote><pre>
insert_return_type insert(node_type&amp;&amp; nh);
</pre></blockquote>
<p>
The <code>insert_return_type</code> is an unspecified type that contains:
</p>
<blockquote><pre>
bool inserted;
X::iterator position;
X::node_type node;
</pre></blockquote>
<p>
As  we can see, the <code>insert</code> function is returning a <code>node</code>. This difference is actually
misleading, as the programmer may start to wonder, why the function returns a <code>node</code> handle, 
instead of being guaranteed that the argument will not be modified (as other functions do). Most reasonable 
explanation is that, this function actually return a handle to a different <code>node</code>, that one passed 
as the argument, i.e. this function replaces an existing node with the <code>nh</code> argument and returns the
handle to the old <code>node</code>. However, this function actually has the same semantics as the other <code>insert</code> 
function and returns a <code>node</code> that was passed as argument.
<p/>
In addition, this design makes the interface of the <code>insert</code> function for the map inconsistent. Value 
inserting functions are returning <code>pair&lt;iterator, bool&gt;</code> while node inserting function is 
returning an unspecified type with guaranteed set of members.
<p/>
The only potential benefit of this signature is that it could potentially allow programmer to use 
decomposition declaration, so instead of:
</p>
<blockquote><pre>
auto nh = node_provider();
if (map.insert(std::move(nh)).second)
  handle_node_in_other_way(std::move(nh));
</pre></blockquote>
<p>
The user would be able to write:
</p>
<blockquote><pre>
if (auto [it, ins, nh] = map.insert(node_provider); ins)
   handle_node_in_other_way(std::move(nh));
</pre></blockquote>
<p>
However, the <code>insert_return_type</code> is not currently required to work with decomposition declaration, so 
this is only "potential" benefit that could be added in future.
<p/>
Furthermore, this change is preventing a user to use structured binding with combination with <code>insert</code> 
in generic code:
</p>
<blockquote><pre>
template&lt;typename UniqMap, typename Elem&gt;
void log_duplicate_insertion(UniqMap&amp; map, Elem&amp;&amp; elem)
{
  if (auto [it, ins] = map.insert(std::forward&lt;Elem&gt;(elem)); !ins)
    std::cout &lt;&lt; "attempt to insert duplicate for " &lt;&lt; *it;
}
</pre></blockquote>
<p>
Currently, <code>log_duplicate_insertion</code> will not work with <code>node_handle_type</code>.
<p/>
So, I am proposing to change the interface of the <code>insert(node_handle)</code> function for associative containers 
with unique keys, to be consistent with the other <code>insert</code> operation and <code>try_emplace</code> function. I.e. 
change the signature to:
</p>
<blockquote><pre>
std::pair&lt;iterator, bool&gt; insert(node_type&amp;&amp; nh);
</pre></blockquote>
<p>
and provide the guarantee that <code>nh</code> will be unchanged if an element was not inserted.
</p>

<p><i>[2016-09-06, Howard comments]</i></p>

<p>
This is related to LWG <a href="lwg-defects.html#839" title="Maps and sets missing splice operation (Status: Resolved)">839</a><sup><a href="https://cplusplus.github.io/LWG/issue839" title="Latest snapshot">(i)</a></sup>.
</p>

<p><i>[2018-1-26 issues processing telecon]</i></p>

<p>Status to 'NAD'; this is "specified as designed". This was considered during the design, but not accepted.</p>


<p id="res-2772"><b>Proposed resolution:</b></p>






</body>
</html>
