<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Issue 438: Ambiguity in the "do the right thing" clause</title>
<meta property="og:title" content="Issue 438: Ambiguity in the &quot;do the right thing&quot; clause">
<meta property="og:description" content="C++ library issue. Status: CD1">
<meta property="og:url" content="https://cplusplus.github.io/LWG/issue438.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="438"><a href="lwg-defects.html#438">438</a>. Ambiguity in the "do the right thing" clause</h3>
<p><b>Section:</b> 23.2.4 <a href="https://wg21.link/sequence.reqmts">[sequence.reqmts]</a> <b>Status:</b> <a href="lwg-active.html#CD1">CD1</a>
 <b>Submitter:</b> Howard Hinnant <b>Opened:</b> 2003-10-20 <b>Last modified:</b> 2016-01-28</p>
<p><b>Priority: </b>Not Prioritized
</p>
<p><b>View other</b> <a href="lwg-index-open.html#sequence.reqmts">active issues</a> in [sequence.reqmts].</p>
<p><b>View all other</b> <a href="lwg-index.html#sequence.reqmts">issues</a> in [sequence.reqmts].</p>
<p><b>View all issues with</b> <a href="lwg-status.html#CD1">CD1</a> status.</p>
<p><b>Discussion:</b></p>

<p>Section 23.2.4 <a href="https://wg21.link/sequence.reqmts">[sequence.reqmts]</a>, paragraphs 9-11, fixed up the problem
noticed with statements like:</p>
<pre>
vector&lt;int&gt; v(10, 1);
</pre>

<p>The intent of the above statement was to construct with:</p>
<pre>
vector(size_type, const value_type&amp;);
</pre>

<p>but early implementations failed to compile as they bound to:</p>
<pre>
template &lt;class InputIterator&gt;
vector(InputIterator f, InputIterator l);
</pre>
<p>instead.</p>

<p>Paragraphs 9-11 say that if InputIterator is an integral type, then the
member template constructor will have the same effect as:</p>
<pre>
vector&lt;static_cast&lt;size_type&gt;(f), static_cast&lt;value_type&gt;(l));
</pre>
<p>(and similarly for the other member template functions of sequences).</p>

<p>There is also a note that describes one implementation technique:</p>
<blockquote><p>
   One way that sequence implementors can satisfy this requirement is to
   specialize the member template for every integral type.
</p></blockquote>

<p>This might look something like:</p>
<blockquote>
<pre>
template &lt;class T&gt;
struct vector
{
     typedef unsigned size_type;

     explicit vector(size_type) {}
     vector(size_type, const T&amp;) {}

     template &lt;class I&gt;
     vector(I, I);

     // ...
};

template &lt;class T&gt;
template &lt;class I&gt;
vector&lt;T&gt;::vector(I, I) { ... }

template &lt;&gt;
template &lt;&gt;
vector&lt;int&gt;::vector(int, int) { ... }

template &lt;&gt;
template &lt;&gt;
vector&lt;int&gt;::vector(unsigned, unsigned) { ... }

//  ...
</pre>
</blockquote>

<p>Label this solution 'A'.</p>

<p>The standard also says:</p>
<blockquote><p>
 Less cumbersome implementation techniques also exist.
</p></blockquote>
<p>
A popular technique is to not specialize as above, but instead catch
every call with the member template, detect the type of InputIterator,
and then redirect to the correct logic.  Something like:
</p>
<blockquote>
<pre>
template &lt;class T&gt;
template &lt;class I&gt;
vector&lt;T&gt;::vector(I f, I l)
{
     choose_init(f, l, int2type&lt;is_integral&lt;I&gt;::value&gt;());
}

template &lt;class T&gt;
template &lt;class I&gt;
vector&lt;T&gt;::choose_init(I f, I l, int2type&lt;false&gt;)
{
    // construct with iterators
}

template &lt;class T&gt;
template &lt;class I&gt;
vector&lt;T&gt;::choose_init(I f, I l, int2type&lt;true&gt;)
{
    size_type sz = static_cast&lt;size_type&gt;(f);
    value_type v = static_cast&lt;value_type&gt;(l);
    // construct with sz,v
}
</pre>
</blockquote>

<p>Label this solution 'B'.</p>

<p>Both of these solutions solve the case the standard specifically
mentions:</p>
<pre>
vector&lt;int&gt; v(10, 1);  // ok, vector size 10, initialized to 1
</pre>

<p>
However, (and here is the problem), the two solutions have different
behavior in some cases where the value_type of the sequence is not an
integral type.  For example consider:
</p>
<blockquote><pre>
     pair&lt;char, char&gt;                     p('a', 'b');
     vector&lt;vector&lt;pair&lt;char, char&gt; &gt; &gt;   d('a', 'b');
</pre></blockquote>
<p>
The second line of this snippet is likely an error.  Solution A catches
the error and refuses to compile.  The reason is that there is no
specialization of the member template constructor that looks like:
</p>
<pre>
template &lt;&gt;
template &lt;&gt;
vector&lt;vector&lt;pair&lt;char, char&gt; &gt; &gt;::vector(char, char) { ... }
</pre>

<p>
So the expression binds to the unspecialized member template
constructor, and then fails (compile time) because char is not an
InputIterator.
</p>

<p>
Solution B compiles the above example though.  'a' is casted to an
unsigned integral type and used to size the outer vector.  'b' is
static casted to the inner vector using it's explicit constructor:
</p>

<pre>
explicit vector(size_type n);
</pre>

<p>
and so you end up with a static_cast&lt;size_type&gt;('a') by
static_cast&lt;size_type&gt;('b') matrix.
</p>

<p>
It is certainly possible that this is what the coder intended.  But the
explicit qualifier on the inner vector has been thwarted at any rate.
</p>

<p>
The standard is not clear whether the expression:
</p>

<pre>
     vector&lt;vector&lt;pair&lt;char, char&gt; &gt; &gt;   d('a', 'b');
</pre>

<p>
(and similar expressions) are:
</p>

<ol>
<li>  undefined behavior.</li>
<li>  illegal and must be rejected.</li>
<li>  legal and must be accepted.</li>
</ol>

<p>My preference is listed in the order presented.</p>

<p>There are still other techniques for implementing the requirements of
paragraphs 9-11, namely the "restricted template technique" (e.g.
enable_if).  This technique is the most compact and easy way of coding
the requirements, and has the behavior of #2 (rejects the above
expression).
</p>

<p>
Choosing 1 would allow all implementation techniques I'm aware of.
Choosing 2 would allow only solution 'A' and the enable_if technique.
Choosing 3 would allow only solution 'B'.
</p>

<p>
Possible wording for a future standard if we wanted to actively reject
the expression above would be to change "static_cast" in paragraphs
9-11 to "implicit_cast" where that is defined by:
</p>

<blockquote>
<pre>
template &lt;class T, class U&gt;
inline
T implicit_cast(const U&amp; u)
{
     return u;
}
</pre>
</blockquote>



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

<p>Replace 23.2.4 <a href="https://wg21.link/sequence.reqmts">[sequence.reqmts]</a> paragraphs 9 - 11 with:</p>

<p>For every sequence defined in this clause and in clause lib.strings:</p>

<ul>
  <li>
    <p>If the constructor</p>
       <pre>
       template &lt;class InputIterator&gt;
       X(InputIterator f, InputIterator l,
         const allocator_type&amp; a = allocator_type())
       </pre>
    <p>is called with a type InputIterator that does not qualify as
    an input iterator, then the constructor will behave as if the
    overloaded constructor:</p>
       <pre>
       X(size_type, const value_type&amp; = value_type(),
         const allocator_type&amp; = allocator_type())
       </pre>
    <p>were called instead, with the arguments static_cast&lt;size_type>(f), l and a, respectively.</p>
  </li>

  <li>
    <p>If the member functions of the forms:</p>
       <pre>
       template &lt;class InputIterator&gt;          //  such as  insert()
       rt fx1(iterator p, InputIterator f, InputIterator l);

       template &lt;class InputIterator&gt;          //  such as  append(), assign()
       rt fx2(InputIterator f, InputIterator l);

       template &lt;class InputIterator&gt;          //  such as  replace()
       rt fx3(iterator i1, iterator i2, InputIterator f, InputIterator l);
       </pre>
    <p>are called with a type InputIterator that does not qualify as
    an input iterator, then these functions will behave as if the
    overloaded member functions:</p>
       <pre>
       rt fx1(iterator, size_type, const value_type&amp;);

       rt fx2(size_type, const value_type&amp;);

       rt fx3(iterator, iterator, size_type, const value_type&amp;);
       </pre>
    <p>were called instead, with the same arguments.</p>
  </li>
</ul>

<p>In the previous paragraph the alternative binding will fail if f 
is not implicitly convertible to X::size_type or if l is not implicitly 
convertible to X::value_type.</p>

<p>
The extent to which an implementation determines that a type cannot be
an input iterator is unspecified, except that as a minimum integral
types shall not qualify as input iterators.
</p>



<p><i>[
Kona: agreed that the current standard requires <code>v('a', 'b')</code>
to be accepted, and also agreed that this is surprising behavior.  The
LWG considered several options, including something like
implicit_cast, which doesn't appear to be quite what we want.  We
considered Howards three options: allow acceptance or rejection,
require rejection as a compile time error, and require acceptance.  By
straw poll (1-6-1), we chose to require a compile time error.
Post-Kona: Howard provided wording.
]</i></p>


<p><i>[
Sydney: The LWG agreed with this general direction, but there was some
discomfort with the wording in the original proposed resolution.
Howard submitted new wording, and we will review this again in
Redmond.
]</i></p>


<p><i>[Redmond: one very small change in wording: the first argument
  is cast to size_t.  This fixes the problem of something like
  <code>vector&lt;vector&lt;int> >(5, 5)</code>, where int is not 
  implicitly convertible to the value type.]</i></p>




<p><b>Rationale:</b></p>
<p>The proposed resolution fixes:</p>

<pre>
  vector&lt;int&gt; v(10, 1);
</pre>

<p>
since as integral types 10 and 1 must be disqualified as input
iterators and therefore the (size,value) constructor is called (as
if).</p>

<p>The proposed resolution breaks:</p>

<pre>
  vector&lt;vector&lt;T&gt; &gt; v(10, 1);
</pre>

<p>
because the integral type 1 is not *implicitly* convertible to
vector&lt;T&gt;.  The wording above requires a diagnostic.</p>

<p>
The proposed resolution leaves the behavior of the following code
unspecified.
</p>

<pre>
  struct A
  {
    operator int () const {return 10;}
  };

  struct B
  {
    B(A) {}
  };

  vector&lt;B&gt; v(A(), A());
</pre>

<p>
The implementation may or may not detect that A is not an input
iterator and employee the (size,value) constructor.  Note though that
in the above example if the B(A) constructor is qualified explicit,
then the implementation must reject the constructor as A is no longer
implicitly convertible to B.
</p>





</body>
</html>
