<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <style type="text/css">
    code {
      border: 2px solid #d0d0d0;
      background-color: LightYellow;
      padding: 2px;
      padding-left: 10px;
      display:table;
      white-space:pre;
      margin:2px;
      margin-bottom:10px;
    }
    blockquote {
      border-left: 2px solid #d0d0d0;
      padding-left: 10px;
      margin: 0;
    }
    table { border-collapse:collapse; }
    table.tbl, table.tbl th, table.tbl td {
      border: 1px solid black;
      padding: 5px
    }
  </style>
  <title>Checking for Existence of an Element in Associative Containers</title>
</head>
<body>

<table>
  <tr>
    <td width="172" align="left" valign="top">Document number:</td>
    <td width="435">P0458R0</td>
  </tr>
  <tr>
    <td width="172" align="left" valign="top">Date:</td>
    <td width="435">2016-10-09</td>
  </tr>
  <tr>
    <td width="172" align="left" valign="top">Project:</td>
    <td width="435">LEWG</td>
  </tr>
  <tr>
    <td width="172" align="left" valign="top">Reply-to:</td>
    <td width="435">Mikhail Maltsev
        &lt;<a href="mailto:maltsevm@gmail.com">maltsevm@gmail.com</a>&gt;</td>
  </tr>
</table>

<h1>Checking for Existence of an Element in Associative Containers</h1>

<p><ol>
  <li><a href="#abstract">Abstract</a></li>
  <li><a href="#motivation">Motivation</a></li>
  <li>
    <a href="#design">Design considerations</a>
    <ol>
      <li><a href="#design-mem-fn">Member function vs free function</a></li>
      <li><a href="#design-iter-bool">Make iterators convertible to bool</a></li>
    </ol>
  </li>
  <li>
    <a href="#wording">Wording</a>
    <ol>
      <li><a href="#wording-cont-req">Container requirements</a></li>
      <li><a href="#wording-assoc">Associative containers</a></li>
      <li><a href="#wording-unord">Unordered associative containers</a></li>
    </ol>
  </li>
  <li><a href="#references">References</a></li>
</ol></p>

<h2><a name="abstract">1. Abstract</a></h2>

<p>This paper proposes to add a member function <tt>contains</tt>, which checks,
whether or not a given element exists in a container, to standard associative
containers.</p>

<h2><a name="motivation">2. Motivation</a></h2>

<p>The common idiom for checking whether an element exists in an associative container
involves doing a lookup and checking the returned iterator:</p>

<code>if (some_set.find(element) != some_set.end()) {
    // ...
}
</code>

<p>This idiom suffers from excessive boilerplate code and is inferior to
<tt>if (some_set.contains(element))</tt> in terms of expressing intent in
code.</p>

<p>It is also not obvious for beginners. Quoting a question from Stack Overflow
[<a href="#ref-stack-overflow">1</a>]:</p>

<blockquote>
<p>How to check if <tt>std::map</tt> contains a key without doing insert?</p>

<p>The only way I have found to check for duplicates is by inserting and
checking the <tt>std::pair.second</tt> for false, but the problem is that this
still inserts something if the key is unused, whereas what I want is a
<tt>map.contains(key);</tt> function.</p>
</blockquote>

<p>Another (a little less common) way to perform the same task is using the
<tt>count</tt> method. Unfortunately, it's use is suboptimal for multisets and
multimaps (it has greater complexity than <tt>find</tt>). In some sense it is
similar to the <tt>size</tt> method of the standard library containers: it does
not replace the <tt>empty</tt> method.

<p>The idea of this proposal is not new. It was discussed on
&quot;std-proposals&quot; forum [<a href="#ref-discuss">2</a>],
but unfortunately that discussion did not result in a formal proposal.</p>

<p>Qt library includes <tt>QSet</tt> and <tt>QMap</tt> class templates, similar
to the standard ones, but they also provide <tt>contains</tt> member function
[<a href="#ref-qt">3</a>].</p>

<p>As Thiago Macieira (one of Qt developers) pointed out in
[<a href="#ref-discuss">2</a>], in Qt itself, <tt>contains</tt> method is used
much more widely than <tt>find</tt>.</p>

<p>Arguably, for sets (<tt>std::set</tt> and <tt>std::unordered_set</tt>) testing
a key for existence is much more common than using the <tt>find</tt> method for
any other purpose, yet it has less obvious API.</p>

<h2><a name="design">3. Design considerations</a></h2>

<h3><a name="design-mem-fn">3.1. Member function vs free function</a></h3>

<p><tt>contains</tt> could as well be added as a free function. One might
even argue, that decoupling of algorithms and containers is one of the core
principles of the standard library. Nevertheless, lookup by key is
inherent to associative containers, i.e. <tt>find</tt> member function is not
equivalent to <tt>std::find</tt>. So, if we were to add <tt>std::contains</tt>,
it should work on ranges and be equivalent to
<tt>std::find(first,&nbsp;last,&nbsp;element)&nbsp;!=&nbsp;last</tt>
for consistency.

<h3><a name="design-iter-bool">3.2. Make iterators convertible to bool</a></h3>

<p>Another (non-)option would be to make iterators returned by associative
containers contextually convertible to bool, i.e. make

<code>if (some_set.find(element))</code>
<p>equivalent to</p>
<code>if (some_set.find(element) != some_set.end())</code>

<p>In some implementations adding such a conversion would be possible without
breaking the ABI. For example, this would definitely be possible for unordered
associative containers in GCC (libstdc++'s <tt>unordered_set::iterator</tt>
consists of a single pointer and for <tt>unordered_set::end</tt> this pointer
is <tt>nullptr</tt>). Unfortunately this might not be the case in general, so
this option is not proposed</p>

<h2><a name="wording">4. Wording</a></h2>

<h3><a name="wording-cont-req">4.1. Container requirements</a></h3>

<p>In [associative.reqmts], &quot;Table 86 — Associative container requirements
(in addition to container)&quot;, add:</p>

<table class="tbl" align="center">
  <tr>
    <th>Expression</th>
    <th>Return type</th>
    <th>Assertion/note pre-/post-condition</th>
    <th>Complexity</th>
  </tr>
  <tr>
    <td><tt>b.contains(k)</tt></td>
    <td><tt>bool</tt></td>
    <td>equivalent to <tt>b.find(k) != b.end()</tt></td>
    <td>logarithmic</td>
  </tr>
</table>

<p>In [unord.req], &quot;Table 87 — Unordered associative container requirements
(in addition to container)&quot;, add:</p>

<table class="tbl" align="center">
  <tr>
    <th>Expression</th>
    <th>Return type</th>
    <th>Assertion/note pre-/post-condition</th>
    <th>Complexity</th>
  </tr>
  <tr>
    <td><tt>b.contains(k)</tt></td>
    <td><tt>bool</tt></td>
    <td>equivalent to <tt>b.find(k) != b.end()</tt></td>
    <td>Average case O(1), worst case O(b.size())</td>
  </tr>
</table>

<h3><a name="wording-assoc">4.2. Associative containers</a></h3>

<p>In [map.overview], in section &quot;map operations&quot; add:</p>
<pre>
  bool contains(const key_type&amp; x) const;
  template &lt;class K&gt; bool contains(const K&amp; x) const;
</pre>

<p>In [multimap.overview], in section &quot;map operations&quot; add:</p>
<pre>
  bool contains(const key_type&amp; x) const;
  template &lt;class K&gt; bool contains(const K&amp; x) const;
</pre>

<p>In [set.overview], in section &quot;set operations&quot; add:</p>
<pre>
  bool contains(const key_type&amp; x);
  template &lt;class K&gt; bool contains(const K&amp; x) const;
</pre>

<p>In [multiset.overview], in section &quot;set operations&quot; add:</p>
<pre>
  bool contains(const key_type&amp; x);
  template &lt;class K&gt; bool contains(const K&amp; x) const;
</pre>

<h3><a name="wording-unord">4.3. Unordered associative containers</a></h3>

<p>In [unord.map.overview], in section &quot;map operations&quot; add:</p>
<pre>
  bool contains(const key_type&amp; k) const;
</pre>

<p>In [unord.multimap.overview], in section &quot;map operations&quot; add:</p>
<pre>
  bool contains(const key_type&amp; k) const;
</pre>

<p>In [unord.set.overview], in section &quot;set operations&quot; add:</p>
<pre>
  bool contains(const key_type&amp; k) const;
</pre>

<p>In [unord.multiset.overview], in section &quot;set operations&quot; add:</p>
<pre>
  bool contains(const key_type&amp; k) const;
</pre>

<h2><a name="references">5. References</a></h2>

<p><ol>
  <li>
    <a name="ref-stack-overflow"></a>Stack Overflow question: How to check if std::map contains a key without doing insert?
    <a href="http://stackoverflow.com/questions/3886593/how-to-check-if-stdmap-contains-a-key-without-doing-insert">
      http://stackoverflow.com/questions/3886593/how-to-check-if-stdmap-contains-a-key-without-doing-insert</a>
  </li>
  <li>
    <a name="ref-discuss"></a>ISO C++ Standard - Future Proposals.
    Isn't it time we had the bool std::[container]::contains() family of methods?
    <a href="https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/set$20contains/std-proposals/onDKXlivhhk/dSjfU0onMNUJ">
      https://groups.google.com/a/isocpp.org/forum/#!searchin/std-proposals/set$20contains/std-proposals/onDKXlivhhk/dSjfU0onMNUJ
    </a>
  </li>
  <li>
    <a name="ref-qt"></a>Qt Documentation. QSet Class,
    <a href="http://doc.qt.io/qt-5/qset.html">
    http://doc.qt.io/qt-5/qset.html</a>
  </li>
</ol></p>

</body>
</html>
