<!DOCTYPE html>
<html lang="en"><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <style>

.comment { color: #999999; font-style: italic; }
.pre { color: #000099; }
.string { color: #009900; }
.char { color: #009900; }
.float { color: #996600; }
.int { color: #999900; }
.bool { color: #000000; font-weight: bold; }
.type { color: #FF6633; }
.flow { color: #FF0000; }
.keyword { color: #990000; }
.operator { color: #663300; font-weight: bold; }
.operator { color: #663300; font-weight: bold; }
pre.code {
    border: 2px solid #666;
    background-color: #F4F4F4;
    padding-left: 10px;
    padding-top: 0px;
}
code {
    border: 2px solid #d0d0d0;
    background-color: LightYellow;
    padding: 2px;
    padding-left: 10px;
    display:table;
    white-space:pre;
    margin:2px;
    margin-bottom:10px;
}
dt {
    font-weight: bold;
}
.ins {
    background-color:#A0FFA0;
}
.del {
    background-color:#FFA0A0;
    text-decoration:line-through
}
.TODO {
    background-color: LightYellow;
    color: red;
}
	  
</style>

<title>Refining standard library support for Class Template Argument Deduction</title>
</head>

<body>
<p>Document number: P1069R0 <br>
Date: 2018-10-08<br>
Reply-To:<br>
&nbsp;&nbsp;&nbsp;Mike Spertus, Symantec (<a href="mailto:mike_spertus@symantec.com">mike_spertus@symantec.com</a>)<br>
&nbsp;&nbsp;&nbsp;Walter E. Brown (<a href="mailto:webrown.cpp@gmail.com"> webrown.cpp@gmail.com</a>)<br>
&nbsp;&nbsp;&nbsp;Stephan T. Lavavej (<a href="mailto:stl@exchange.microsoft.com">stl@exchange.microsoft.com</a>)<br>
Audience: {Library Evolution, Library} Working Group
</p>

<h1>Refining standard library support for Class Template Argument Deduction</h1>
<h2>Introduction</h2>
<p> In this paper, we describe the changes to library support for class template argument deduction
    that we believe are appropriate for C++20. <ul>
    <li>Adding new
    overloads to <tt>make_unique</tt> and <tt>make_shared</tt> to support an important
    use case</li>
    <li>(Re)adding some container constructors in support of   P1021R1, which (if adopted) we
    hope will provide a powerful use case for supporting deduction
    from allocators that did not exist in C++17.</li> 
    <li>Finally, while we think the committee did an exceptional job on standard library
        deduction guides in C++17 and there is very little that we would have changed
        in retrospect except for one decision (the
        handling of <tt>reference_wrapper</tt>s) that we feel should
        be corrected. We present a rationale that we believe was not discussed at the time in
    support of this</li></ul>

<h2>Overloading <tt>make_unique</tt> and <tt>make_shared</tt></h2>
While class template argument deduction can be used for
    objects with static and automatic duration, it generally cannot be  
    used for creating objects with dynamic duration as the following attempts show:

    <code>optional o(5); // OK. Static duration. optional&lt;int&gt;
        
// Try to create dynamic duration object.
auto o1 = new optional(5);  // Already violates both Core Guidelines <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-ptr">R.3</a> and <a href="https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#Rr-newdelete">R.11</a><br>
<strike>auto o2 = unique_ptr(o1);</strike> // Oops, ill-formed. Can't deduce unique_ptr from raw ptr</code>

We propose simply making dynamic object creation with <tt>make_unique</tt> and <tt>make_shared</tt>
work just like the normal way one would translate a static and automatic declaration to a dynamic
declaration
<code>int i1(5);                       // Static
auto i2 = make_unique&lt;int&gt;(5);   // Make dynamic by moving decl-specifier to make_unique template argument
option o1(5);
auto o2 = make_unique&lt;optional&gt;(5); // Again, make dynamic by moving decl-specifier to make_unique template argument</code>
Implementing this can be as simple as the following code, which can be seen working on <a href="https://wandbox.org/permlink/jn49SA7tlDO02gcw">Wandbox</a>
<code>template&lt;template &lt;typename ...U&gt; typename T, typename ...A&gt;
auto make_unique(A&amp;&amp; ...a) {
    return std::unique_ptr&lt;decltype(T(std::forward&lt;A&gt;(a)...))&gt;(new T(std::forward&lt;A&gt;(a)...));
}</code>
<b>Notes:</b>
<ul><li>For simplicity, we do not propose supporting the case of non-type template parameters as
    it is far less frequent and seems far more complex.
    If and only if library implementers feel that there are no implementation concerns for non-type
    template parameters, then that should be supported as well</li>
    <li>It is worth pointing out that because this code exactly matches <em>mutatis mutandi</em> the automatic duration
    declaration case, it should have no cause to be in any way more dangerous or confusing
    that what is supported for objects created with static or automatic duration</li></ul>
<!-- <h2>Decay from arrays</h2>
As Nico Josuttis has pointed out, the following code throws a run-time error
    instead of a compile-time error as expected (<a href="https://wandbox.org/permlink/jRLmw7StRIoJe7w5">wandbox</a>):
<code>    vector v("foo", "bar");
    for(auto x : v) {
        cout &lt;&lt; x;
    }</code>
The surprising point is that the two character arrays decay to pointers and are therefore
interpreted as iterators into a <tt>vector&lt;char&gt;</tt>. We propose simply specifying that
    the containers should not succeed in deducing from two arrays where iterators are expected. -->
<h2>Allow containers to deduce from allocators or comparators</h2>
    <b>Note:</b> This item has a dependency on <a href="http://wg21.link/p1021r1">P1021R1</a> as described
    below.<p>A number of associative container guides were removed in the late stages of the Kona meeting
    for the following reasons
    <ul><li>Since the <tt>size_type</tt> member may or may not be a deduced context,
    and different compilers handle “most specialized” differently when some candidates
        are deducible and others are non-deducible for the same argument, there were implementability concerns.</li> 
    <li>Even where there were no implementability concerns,
        construction from allocators was removed from all other containers for consistency with
        associative containers.</li>
    <li>A general agreement that trying to deduce the value type for a container from its
        allocator was an anti-pattern</li>
    <li>In addition, there were no constructors from comparators because the value type
        could not be deduced from a comparator anyway.</li></ul>

	<p>We propose restoring guides so that containers deduce consistently from all of their constructors
        not because we disagree with any of the above, but because P1021R1's support
        for partial specialization in class template argument deduction, if accepted, adds a very important 
        and useful new use case for them.
        <code>vector&lt;int&gt; v{MyAlloc{}}; // Want vector&lt;int, MyAlloc&gt;
set&lt;string&gt; caseInsensitiveStrings([](string const &amp;a, string const &amp;b) { /* ... */ });</code>
	Speaking &ldquo;conceptually&rdquo;, we also suggest that deducing correctly
        from all constructors is valuable because the reason that STL containers need a lot of deduction guides in the first place is because they are not conceptized (See the bottom of <a href="http://qr.w69b.com/g/qE1JDD0Sk">http://qr.w69b.com/g/qE1JDD0Sk</a> for a demonstration
		of some current deduction guides becoming unnecessary in a conceptized STL). If we ever have a concept-enabled STL, then the example in use case 1 above will work even without a deduction guide, so this is not only useful now but better prepares us for the future concepts vision.
    
     <p>The new deduction guides are similar to the previously removed deduction guides with the 
         following changes, which incidentally greatly simplify their original versions:
         <ul><li>To steer clear of the technical concern mention above, we simply use <tt>size_t</tt> in the following wording
    (Note that using <tt>size_t</tt> does not assume that the container's <tt>size_type</tt> is <tt>size_t</tt>,
		just that it is just an integral type being used for overload resolution).</li>
    <li>We do not attempt to deduce the value type from the allocator. This is sufficient
             for the new use cases and steers clear of the above concern</li>
    <li>We also add deduction from comparators</li></ul>

<h2><tt>reference_wrapper</tt> and <tt>pair/tuple</tt> deduction</h2>
<p>In <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0433r0.html">P0433R0</a>, it was proposed that deduction guides for <tt>pair</tt> and <tt>tuple</tt> unwrap <tt>reference_wrapper</tt> like <tt>make_pair</tt> and <tt>make_tuple</tt> do. Such unwrapping was removed from later revisions of the paper and not adopted in C++17. According to both the minutes and the mailing list, unwrapping was suppressed in order to increase applicability to fully generic programming. However, as the following code available at <a href="https://wandbox.org/permlink/rRITtZ2gT2ZqR4jY">https://wandbox.org/permlink/rRITtZ2gT2ZqR4jY</a> shows, the possibility of picking up stray constructors suggests that fully generic programming should fully specialize template parameters anyway (note that this best practice is not limited to CTAD) rather than relying on <tt>tuple</tt> CTAD.</p>

<code>template&lt;typename ...T&gt;  // CTAD: Intends tuple&lt;T...&gt; but stray constructors make unreliable
using ctad = decltype(tuple{declval&lt;T&gt;()...}); 

template&lt;typename ...T&gt;  // Explicit:  Produces tuple&lt;T...&gt; as intended
using expl = decltype(tuple&lt;T...&gt;{declval&lt;T&gt;()...});

int main()
{
    print_type&lt;ctad&lt;tuple&lt;lt;int&gt;&gt;&gt;();  // std::tuple&lt;int&gt;
    print_type&lt;expl&lt;tuple&lt;int&gt;&gt;&gt;();  // std::tuple&lt;std::tuple&lt;int&gt;&gt;
    print_type&lt;ctad&lt;allocator_arg_t, allocator&lt;int&gt;, int&gt;&gt;();  // std::tuple&lt;int&gt;
    print_type&lt;expl&lt;allocator_arg_t, allocator&lt;int&gt;, int&gt;&gt;();  // std::tuple&lt;std::allocator_arg_t, std::allocator&lt;int&gt;, int&gt;
    return 0;
}
</code>	
	<p>However, with the C++17 behavior, not only does <tt>pair/tuple</tt> deduction not support generic metaprogramming, its inability to deduce references limits its ability to replace <tt>make_tuple</tt> or <tt>make_pair</tt> even though many expositions  (E.g., [<a href="https://arne-mertz.de/2017/06/class-template-argument-deduction/">1</a>], [<a href="https://blog.tartanllama.xyz/deduction-for-class-templates/">2</a>], and [<a href="https://tech.io/playgrounds/2205/7-features-of-c17-that-will-simplify-your-code/template-argument-deduction-for-class-templates">3</a>]) give <tt>make_pair</tt> replacement as their motivating use case. As library vocabulary vocabulary types whose pre-CTAD factory functions unwrap <tt>reference_wrapper</tt>, we suggest that behavior preserved in CTAD.</p>

<h3>Wording</h3>
    In addition to the below, change all of the &ldquo;<em>see below</em>::size_type&rdquo;
    with <tt>size_t</tt> in deduction guides, simplifying and increasing robustness<p>
    Add the following deduction guide to the definition of class <tt>basic_string</tt> in
    &sect;24.3.2 [basic.string]:
    
    </p><blockquote><pre>    int compare(size_type pos1, size_type n1,
                const charT* s, size_type n2) const;
  };
  
<span class="ins">template&lt;class T, class Traits = char_traits&lt;T&gt;, class Allocator&gt;
basic_string(Allocator) -&gt; basic_string&lt;T, Traits, Allocator&gt;;
</span></pre></blockquote>
In &sect;24.3.2.2 [string.cons], insert the following:
<blockquote><pre><span class="ins">template&lt;class T,  class Traits = char_traits&lt;T&gt;, class Allocator&gt;
basic_string(Allocator) -&gt; basic_string&lt;T, Traits, Allocator&gt;;
</span></pre>
    <blockquote><span class="ins"><em>Remarks:</em> Shall not participate in overload resolution if <tt>Allocator</tt> is a type that does not qualify as an allocator [sequence.reqmts].</span></blockquote></blockquote>

At the end of the definition of class <tt>deque</tt> in &sect;26.3.8.1 [deque.overview], add
    the following deduction guides:
<blockquote><pre>  void clear() noexcept;
};

<span class="ins">template&lt;class T, class Allocator&gt; 
explicit deque(Allocator) -&gt; deque&lt;T, Allocator&gt;;
  
template&lt;class T, class Allocator&gt; explicit deque(size_t, Allocator) -&gt; deque&lt;T, Allocator&gt;;</span></pre></blockquote>
    
    
At the end of the definition of class <tt>forward_list</tt> in &sect;26.3.9.1 [forwardlist.overview],
add the following deduction guides:
<blockquote><pre>    void reverse() noexcept;
  };
  
<span class="ins">  template&lt;class T, class Allocator&gt;
  explicit forward_list(Allocator) -&gt; forward_list&lt;T, Allocator&gt;;
  
  template&lt;class T, class Allocator&gt; 
  explicit forward_list(size_t, Allocator) -&gt; forward_list&lt;T, Allocator&gt;;</span></pre></blockquote>
    
At the end of the definition of class <tt>list</tt> in &sect;26.3.10.1 [list.overview],
add the following deduction guides:
<blockquote><pre>    void reverse() noexcept;
  };
  
<span class="ins">  template&lt;class T, class Allocator&gt;
  explicit list(Allocator) -&gt; list&lt;T, Allocator&gt;;
  
  template&lt;class T, class Allocator&gt; 
  explicit list(size_t, Allocator) -&gt; list&lt;T, Allocator&gt;;</span></pre></blockquote>

At the end of the definition of class <tt>vector</tt> in &sect;26.3.11.1 [vector.overview],
add the following <em>deduction-guide</em>:
<blockquote><pre>    void clear() noexcept;
  };
  
<span class="ins">  template&lt;class T, class Allocator&gt;
  explicit  vector(Allocator) -&gt; vector&lt;T, Allocator&gt;;
  
  template&lt;class T, class Allocator&gt; 
  explicit  vector(size_t, Allocator)
    -&gt; vector&lt;T, Allocator&gt;;</span></pre></blockquote>

   
At the end of the definition of class <tt>map</tt> in &sect;26.4.4.1 [map.overview],
add the following deduction guides:
    
<blockquote><pre>    pair&lt;const_iterator, const_iterator&gt; equal_range(const K&amp; x) const;
  };
  
<span class="ins">  template&lt;class Key, class T, class Compare, class Allocator = allocator&lt;pair&lt;Key, T&gt;&gt;&gt;  
  explicit map(Compare, Allocator = Allocator())
    -&gt; map&lt;Key, T, Compare, Allocator&gt;;</span> 
      
<span class="ins">  template&lt;class Key, class T, class Compare = less&lt;Key&gt;, class Allocator&gt;
  explicit map(Allocator)
    -&gt; map&lt;Key, T, Compare, Allocator&gt;;</span></pre></blockquote>  

    
At the end of the definition of class <tt>multimap</tt> in &sect;26.4.5.1 [multimap.overview],
add the following deduction guides:
    
<blockquote><pre>    pair&lt;const_iterator, const_iterator&gt; equal_range(const K&amp; x) const;
  };
  
<span class="ins">  template&lt;class Key, class T, class Compare, class Allocator = allocator&lt;pair&lt;Key, T&gt;&gt;&gt;  
  explicit multimap(Compare, Allocator = Allocator())
    -&gt; multimap&lt;Key, T, Compare, Allocator&gt;;</span> 
      
<span class="ins">  template&lt;class Key, class T, class Compare = less&lt;Key&gt;, class Allocator&gt;
  explicit multimap(Allocator)
    -&gt; multimap&lt;Key, T, Compare, Allocator&gt;;</span></pre></blockquote>  

At the end of the definition of class <tt>set</tt> in &sect;26.4.6.1 [set.overview],
add the following <em>deduction-guide</em>s:
<blockquote><pre>    template &lt;class K&gt;
      pair&lt;const_iterator, const_iterator&gt; equal_range(const K&amp; x) const;
  };
  
<span class="ins">  template&lt;class T, class Compare, class Allocator&gt;
  explicit set(Compare, Allocator = allocator&lt;T&gt;)
    -&gt; set&lt;T, Compare, Allocator&gt;;</span>

  
<span class="ins">  template&lt;class T, class Compare = less&lt;T&gt;, class Allocator&gt;
  explicit set(Allocator)
    -&gt; set&lt;T, Compare, Allocator&gt;;</span></pre></blockquote>
    
At the end of the definition of class <tt>multiset</tt> in &sect;27.4.6.1 [multiset.overview],
add the following deduction guides:
<blockquote><pre>    template &lt;class K&gt;
      pair&lt;const_iterator, const_iterator&gt; equal_range(const K&amp; x) const;
  };
  
<span class="ins">  template&lt;class T, class Compare, class Allocator&gt;
  explicit multiset(Compare, Allocator = allocator&lt;T&gt;)
    -&gt; multiset&lt;T, Compare, Allocator&gt;;</span>

  
<span class="ins">  template&lt;class T, class Compare = less&lt;T&gt;, class Allocator&gt;
  explicit multiset(Allocator)
    -&gt; multiset&lt;T, Compare, Allocator&gt;;</span></pre></blockquote>
    

Modify &sect;26.5.4.1 [unord.map.overview],
add the following <em>deduction-guide</em>s:
<blockquote><pre>    void reserve(size_type n);
  };
  
<span class="ins">  template&lt;class Key, class T, class Hash = hash&lt;Key&gt;, class Pred = equal_to&lt;Key&gt;, class Allocator&gt;
  explicit unordered_map(size_t, Hash, Pred = Pred(), Allocator = Allocator())
      -&gt; unordered_map&lt;Key, T, Hash, Pred, Allocator&gt;;</span>
      
<span class="ins">  template&lt;class Key, class T, class Hash = hash&lt;Key&gt;, class Pred = equal_to&lt;Key&gt;, class Allocator&gt;
  explicit unordered_map(Allocator)
    -&gt; unordered_map&lt;Key, T, Hash, Pred, Allocator&gt;;</span>


<span class="ins">  template&lt;class Key, class T, class Hash = hash&lt;Key&gt;, class Pred = equal_to&lt;Key&gt;, class Allocator&gt;
  explicit unordered_map(size_t, Allocator)
      -&gt; unordered_map&lt;Key, T, Hash, Pred, Allocator&gt;;
   
  template&lt;class Key, class T, class Hash, class Pred = equal_to&lt;Key&gt;, class Allocator&gt;
  explicit unordered_map(size_t, Hash, Allocator)
    -&gt; unordered_map&lt;Key, T,
	        Hash, Pred, Allocator&gt;;</span></pre></blockquote>

    
Delete &sect;26.5.4.1p4 [unord.map.overview]:
<blockquote><span class="del">A <tt>size_type</tt> parameter type in an <tt>unordered_map</tt> deduction 
    guide refers to the <tt>size_type</tt> member type of the type deduced by the deduction guide.</span></blockquote>

Modify &sect;26.5.5.1 [unord.multimap.overview],
add the following <em>deduction-guide</em>s:
<blockquote><pre>    void reserve(size_type n);
  };
  
<span class="ins">  template&lt;class Key, class T, class Hash = hash&lt;Key&gt;, class Pred = equal_to&lt;Key&gt;, class Allocator&gt;
  explicit unordered_multimap(size_t, Hash, Pred = Pred(), Allocator = Allocator())
      -&gt; unordered_multimap&lt;Key, T, Hash, Pred, Allocator&gt;;</span>
      
<span class="ins">  template&lt;class Key, class T, class Hash = hash&lt;Key&gt;, class Pred = equal_to&lt;Key&gt;, class Allocator&gt;
  explicit unordered_multimap(Allocator)
    -&gt; unordered_multimap&lt;Key, T, Hash, Pred, Allocator&gt;;</span>


<span class="ins">  template&lt;class Key, class T, class Hash = hash&lt;Key&gt;, class Pred = equal_to&lt;Key&gt;, class Allocator&gt;
  explicit unordered_multimap(size_t, Allocator)
      -&gt; unordered_multimap&lt;Key, T, Hash, Pred, Allocator&gt;;

  template&lt;class Key, class T, class Hash, class Pred = equal_to&lt;Key&gt;, class Allocator&gt;
  explicit unordered_multimap(size_t, Hash, Allocator)
    -&gt; unordered_multimap&lt;Key, T,
	        Hash, Pred, Allocator&gt;;</span></pre></blockquote>

    
Delete &sect;26.5.5.1p4 [unord.multimap.overview]:
<blockquote><span class="del">A <tt>size_type</tt> parameter type in an <tt>unordered_multimap</tt> deduction 
    guide refers to the <tt>size_type</tt> member type of the type deduced by the deduction guide.</span></blockquote>
    
    
    
Modify &sect;26.5.6.1 [unord.set.overview] as follows:
<blockquote><pre>    void reserve(size_type n);
  };

<span class="ins">  template&lt;class T, class Hash, class Pred = equal_to&lt;T&gt;, class Allocator = allocator&lt;T&gt;&gt;
  explicit unordered_set(size_t, Hash, Pred = Pred(), Allocator = Allocator())
    -&gt; unordered_set&lt;T, Hash, Pred, Allocator&gt;;</span>

  
<span class="ins">  template&lt;class T, class Hash = hash&lt;T&gt;, Pred = equal_to&lt;T&gt;, class Allocator&gt; 
  explicit unordered_set(size_t, Allocator)
    -&gt; unordered_set&lt;T, Hash, Pred, Allocator&gt;;
  
  template&lt;class T, class Hash, Pred = equal_to&lt;T&gt;, class Allocator&gt; 
  explicit unordered_set(size_t, Hash, Allocator)
    -&gt; unordered_set&lt;T, Hash, Pred, Allocator&gt;;</span>

  </pre></blockquote>
Delete &sect;26.5.6.1p4 [unord.set.overview]:
<blockquote><span class="del">A <tt>size_type</tt> parameter type in an <tt>unordered_set</tt> deduction 
    guide refers to the <tt>size_type</tt> member type of the primary <tt>unordered_set</tt> template.</span></blockquote>

    
Modify &sect;26.5.7.1 [unord.multiset.overview] as follows:
<blockquote><pre>    void reserve(size_type n);
  };

<span class="ins">  template&lt;class T, class Hash, class Pred = equal_to&lt;T&gt;, class Allocator = allocator&lt;T&gt;&gt;
  explicit unordered_multiset(size_t, Hash, Pred = Pred(), Allocator = Allocator())
    -&gt; unordered_multiset&lt;T, Hash, Pred, Allocator&gt;;</span>

  
<span class="ins">  template&lt;class T, class Hash = hash&lt;T&gt;, Pred = equal_to&lt;T&gt;, class Allocator&gt; 
  explicit unordered_multiset(size_t, Allocator)
    -&gt; unordered_multiset&lt;T, Hash, Pred, Allocator&gt;;
  
  template&lt;class T, class Hash, Pred = equal_to&lt;T&gt;, class Allocator&gt; 
  explicit unordered_multiset(size_t, Hash, Allocator)
    -&gt; unordered_multiset&lt;T, Hash, Pred, Allocator&gt;;</span>
  
</pre></blockquote>
Delete &sect;26.5.7.1p4 [unord.multiset.overview]:
<blockquote><span class="del">A <tt>size_type</tt> parameter type in an <tt>unordered_multiset</tt> deduction 
    guide refers to the <tt>size_type</tt> member type of the primary <tt>unordered_multiset</tt> template.</span></blockquote>

At the end of the
definition of class <tt>promise</tt> in &sect;33.6.6 [futures.promise], insert the following:
<blockquote><pre>    <span class="comment">// setting the result with deferred notification</span>
    void set_value_at_thread_exit(<em>see below</em>);
    void set_exception_at_thread_exit(exception_ptr p);
  };
  
<span class="ins">  template &lt;class T, class Alloc&gt; promise(allocator_arg_t, Alloc)
    -&gt; promise&lt;T&gt;;</span>
	
  template &lt;class R&gt;
    void  swap(promise&lt;R&gt;&amp; x,  promise&lt;R&gt;&amp; y) noexcept;
  </pre></blockquote>


</body></html>