<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 307: Lack of reference typedefs in container adaptors</title>
<meta property="og:title" content="Issue 307: Lack of reference typedefs in container adaptors">
<meta property="og:description" content="C++ library issue. Status: CD1">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue307.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#CD1">CD1</a> status.</em></p>
<h3 id="307"><a href="lwg-defects.html#307">307</a>. Lack of reference typedefs in container adaptors</h3>
<p><b>Section:</b> 23.3.11 <a href="https://wg21.link/list">[list]</a> <b>Status:</b> <a href="lwg-active.html#CD1">CD1</a>
 <b>Submitter:</b> Howard Hinnant <b>Opened:</b> 2001-03-13 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View all issues with</b> <a href="lwg-status.html#CD1">CD1</a> status.</p>
<p><b>Discussion:</b></p>

<p>From reflector message c++std-lib-8330.  See also lib-8317.</p>

<p>
The standard is currently inconsistent in 23.3.11.3 <a href="https://wg21.link/list.capacity">[list.capacity]</a>
paragraph 1 and 23.3.11.4 <a href="https://wg21.link/list.modifiers">[list.modifiers]</a> paragraph 1.
23.2.3.3/1, for example, says:
</p>

<blockquote><p>
-1- Any sequence supporting operations back(), push_back() and pop_back() 
can be used to instantiate stack. In particular, vector (lib.vector), list 
(lib.list) and deque (lib.deque) can be used. 
</p></blockquote>

<p>But this is false: vector&lt;bool&gt; can not be used, because the
container adaptors return a T&amp; rather than using the underlying
container's reference type.</p>

<p>This is a contradiction that can be fixed by:</p>

<ol>
<li>Modifying these paragraphs to say that vector&lt;bool&gt;
    is an exception.</li>
<li>Removing the vector&lt;bool&gt; specialization.</li>
<li>Changing the return types of stack and priority_queue to use 
    reference typedef's.</li>
</ol>

<p>
I propose 3.  This does not preclude option 2 if we choose to do it
later (see issue <a href="lwg-closed.html#96" title="Vector&lt;bool&gt; is not a container (Status: NAD)">96</a><sup><a href="https://cplusplus.github.io/LWG/issue96" title="Latest snapshot">(i)</a></sup>); the issues are independent.  Option
3 offers a small step towards support for proxied containers.  This
small step fixes a current contradiction, is easy for vendors to
implement, is already implemented in at least one popular lib, and
does not break any code.
</p>



<p id="res-307"><b>Proposed resolution:</b></p>
<p>Summary: Add reference and const_reference typedefs to queue,
priority_queue and stack.  Change return types of "value_type&amp;" to
"reference".  Change return types of "const value_type&amp;" to
"const_reference".  Details:</p>

<p>Change 23.2.3.1/1 from:</p>

<pre>
  namespace std {
    template &lt;class T, class Container = deque&lt;T&gt; &gt;
    class queue {
    public:
      typedef typename Container::value_type            value_type;
      typedef typename Container::size_type             size_type;
      typedef          Container                        container_type;
    protected:
      Container c;

    public:
      explicit queue(const Container&amp; = Container());

      bool      empty() const             { return c.empty(); }
      size_type size()  const             { return c.size(); }
      value_type&amp;       front()           { return c.front(); }
      const value_type&amp; front() const     { return c.front(); }
      value_type&amp;       back()            { return c.back(); }
      const value_type&amp; back() const      { return c.back(); }
      void push(const value_type&amp; x)      { c.push_back(x); }
      void pop()                          { c.pop_front(); }
    };
</pre>

<p>to:</p>

<pre>
  namespace std {
    template &lt;class T, class Container = deque&lt;T&gt; &gt;
    class queue {
    public:
      typedef typename Container::value_type            value_type;
      typedef typename Container::reference             reference;
      typedef typename Container::const_reference       const_reference;
      typedef typename Container::value_type            value_type;
      typedef typename Container::size_type             size_type;
      typedef          Container                        container_type;
    protected:
      Container c;

    public:
      explicit queue(const Container&amp; = Container());

      bool      empty() const             { return c.empty(); }
      size_type size()  const             { return c.size(); }
      reference         front()           { return c.front(); }
      const_reference   front() const     { return c.front(); }
      reference         back()            { return c.back(); }
      const_reference   back() const      { return c.back(); }
      void push(const value_type&amp; x)      { c.push_back(x); }
      void pop()                          { c.pop_front(); }
    };
</pre>

<p>Change 23.2.3.2/1 from:</p>

<pre>
  namespace std {
    template &lt;class T, class Container = vector&lt;T&gt;,
              class Compare = less&lt;typename Container::value_type&gt; &gt;
    class priority_queue {
    public:
      typedef typename Container::value_type            value_type;
      typedef typename Container::size_type             size_type;
      typedef          Container                        container_type;
    protected:
      Container c;
      Compare comp;

    public:
      explicit priority_queue(const Compare&amp; x = Compare(),
                              const Container&amp; = Container());
      template &lt;class InputIterator&gt;
        priority_queue(InputIterator first, InputIterator last,
                       const Compare&amp; x = Compare(),
                       const Container&amp; = Container());

      bool      empty() const       { return c.empty(); }
      size_type size()  const       { return c.size(); }
      const value_type&amp; top() const { return c.front(); }
      void push(const value_type&amp; x);
      void pop();
    };
                                  //  no equality is provided
  }
</pre>

<p>to:</p>

<pre>
  namespace std {
    template &lt;class T, class Container = vector&lt;T&gt;,
              class Compare = less&lt;typename Container::value_type&gt; &gt;
    class priority_queue {
    public:
      typedef typename Container::value_type            value_type;
      typedef typename Container::reference             reference;
      typedef typename Container::const_reference       const_reference;
      typedef typename Container::size_type             size_type;
      typedef          Container                        container_type;
    protected:
      Container c;
      Compare comp;

    public:
      explicit priority_queue(const Compare&amp; x = Compare(),
                              const Container&amp; = Container());
      template &lt;class InputIterator&gt;
        priority_queue(InputIterator first, InputIterator last,
                       const Compare&amp; x = Compare(),
                       const Container&amp; = Container());

      bool      empty() const       { return c.empty(); }
      size_type size()  const       { return c.size(); }
      const_reference   top() const { return c.front(); }
      void push(const value_type&amp; x);
      void pop();
    };
                                  //  no equality is provided
  }
</pre>

<p>And change 23.2.3.3/1 from:</p>

<pre>
  namespace std {
    template &lt;class T, class Container = deque&lt;T&gt; &gt;
    class stack {
    public:
      typedef typename Container::value_type            value_type;
      typedef typename Container::size_type             size_type;
      typedef          Container                        container_type;
    protected:
      Container c;

    public:
      explicit stack(const Container&amp; = Container());

      bool      empty() const             { return c.empty(); }
      size_type size()  const             { return c.size(); }
      value_type&amp;       top()             { return c.back(); }
      const value_type&amp; top() const       { return c.back(); }
      void push(const value_type&amp; x)      { c.push_back(x); }
      void pop()                          { c.pop_back(); }
    };

    template &lt;class T, class Container&gt;
      bool operator==(const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator&lt; (const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator!=(const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator&gt; (const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator&gt;=(const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator&lt;=(const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
  }
</pre>

<p>to:</p>

<pre>
  namespace std {
    template &lt;class T, class Container = deque&lt;T&gt; &gt;
    class stack {
    public:
      typedef typename Container::value_type            value_type;
      typedef typename Container::reference             reference;
      typedef typename Container::const_reference       const_reference;
      typedef typename Container::size_type             size_type;
      typedef          Container                        container_type;
    protected:
      Container c;

    public:
      explicit stack(const Container&amp; = Container());

      bool      empty() const             { return c.empty(); }
      size_type size()  const             { return c.size(); }
      reference         top()             { return c.back(); }
      const_reference   top() const       { return c.back(); }
      void push(const value_type&amp; x)      { c.push_back(x); }
      void pop()                          { c.pop_back(); }
    };

    template &lt;class T, class Container&gt;
      bool operator==(const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator&lt; (const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator!=(const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator&gt; (const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator&gt;=(const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
    template &lt;class T, class Container&gt;
      bool operator&lt;=(const stack&lt;T, Container&gt;&amp; x,
                      const stack&lt;T, Container&gt;&amp; y);
  }
</pre>

<p><i>[Copenhagen: This change was discussed before the IS was released
and it was deliberately not adopted.  Nevertheless, the LWG believes
(straw poll: 10-2) that it is a genuine defect.]</i></p>






</body>
</html>
