<html>

<head>
  <meta http-equiv="Content-Language" content="en-us">
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  <title>Default Arguments for pair's Forwarding Constructor</title>
</head>

<body>
  <table border="0" cellpadding="0" cellspacing="0" style="border-collapse: collapse" bordercolor="#111111" width="607">
    <tr>
      <td width="172" align="left" valign="top">Document number:</td>
      <td width="435">P1951R0</td>
    </tr>
    <tr>
      <td width="172" align="left" valign="top">Date:</td>
      <td width="435">2019-11-17
      </td>
    </tr>
    <tr>
      <td width="172" align="left" valign="top">Audience:</td>
      <td width="435">LWG</td>
    </tr>
    <tr>
      <td width="172" align="left" valign="top">Reply-to:</td>
      <td width="435">Logan R. Smith &lt;<a href="mailto:logan.r.smith0@gmail.com">logan.r.smith0@gmail.com</a>&gt;</td>
    </tr>
  </table>
  <h1>Default Arguments for <code>pair</code>'s Forwarding Constructor</h1>

  <p><a href="#Introduction">Introduction</a><br>
    <a href="#Motivation">Motivation</a><br>
    <a href="#Impact">Impact</a><br>
    <a href="#Proposed-changes">Proposed Changes</a><br>
    <a href="#Acknowledgements">Acknowledgements</a></p>

  <h2><a name="Introduction">Introduction</a></h2>
  <p>This paper proposes defaulting the template arguments <code>U1</code> and <code>U2</code> in <code>pair</code>'s
    forwarding constructor to
    <code>T1</code> and
    <code>T2</code>
    respectively, so that braced initializers may be used as constructor arguments to it.</p>

  <h2><a name="Motivation">Motivation</a></h2>
  <p>Consider this innocent-looking construction of a <code>std::pair</code>:</p>

  <blockquote><code>std::pair&lt;std::string, std::vector&lt;std::string&gt;&gt; p("hello", {});</code></blockquote>

  <p>This code uses simple, highly natural syntax for the constructor arguments; it is what any C++ programmer, beginner
    or
    expert, would hope to be able to write. During constructor overload resolution, two two-argument constructors (or
    constructor templates) are considered:</p>

  <blockquote><b>(A)</b><code> <i>EXPLICIT</i> constexpr pair(const T1& x, const T2& y);</code></blockquote>

  <p>and</p>

  <blockquote><b>(B)</b><code> template&lt;class U1, class U2&gt; <i>EXPLICIT</i> constexpr pair(U1&& x, U2&& y);</code>
  </blockquote>

  <p>The more efficient option, and the one the user likely hoped would be used, is (B), which takes two forwarding
    references and perfectly forwards them to the constructors of <code>first</code> and <code>second</code>. However,
    since the second
    argument to the constructor was given as <code>{}</code>, the type of <code>U2</code> cannot be deduced, and so (B)
    is
    removed from
    overload resolution and (A) is selected. From there, a temporary <code>std::string</code> and
    <code>std::vector&lt;std::string&gt;</code> are
    created at the call site, and are passed by const reference to be copied into <code>first</code> and
    <code>second</code>. Thus, the
    simplest and easiest code to write results in potentially very inefficient behavior.</p>

  <p>(Note, by contrast, if the pair is constructed using the similar-in-spirit
    <code>p("hello", std::vector&lt;std::string&gt;{})</code>,
    then
    (B) is selected, since <code>U2</code> can be deduced in this case. This subtlety of syntax is surprising and
    user-unfriendly.)</p>

  <p>If (B)'s template arguments were adjusted slightly to default to the pair's first and second type, respectively,
    there would be a fallback when deduction of braced initializers fails. Using the following adjusted signature:</p>

  <blockquote>
    <b>(C)</b><code> template&lt;class U1=T1, class U2=T2&gt; <i>EXPLICIT</i> constexpr pair(U1&& x, U2&& y);</code>
  </blockquote>

  <p>this overload can now be selected for the example case above, so the example pair's string member is constructed
    in-place from a perfectly-forwarded string literal, and its
    vector member is move-constructed instead of copy-constructed from the temporary vector at the call site.</p>

  <p>There is precedent in the standard library for using default template arguments specifically to accommodate
    braced initializers; for instance, <code>std::optional</code>'s forwarding constructor, and the second parameter of
    <code>std::exchange</code>. This paper recommends <code>std::pair</code> adopt this same strategy, for reducing
    surprise and
    making the
    most natural syntax be acceptably efficient.</p>

  <h2><a name="Impact">Impact</a></h2>
  <p>This change would alter the meaning of existing code that uses braced initializers in the construction of pairs,
    likely
    changing copies to moves or perfectly-forwarded constructions in many cases. It is all but certain that this new
    behavior would be welcomed over the old.</p>
  <p>Note that this proposal has no effect on APIs such as <code>std::map::emplace</code> which forward constructor
    arguments to <code>pair</code>, since those APIs need to deduce all argument types on their own first before
    forwarding them. Code such as</p>
  <pre>    std::map&lt;std::string, std::vector&lt;std::string&gt;&gt; m;
    m.emplace("hello", {});
</pre>
  <p>remains ill-formed after this proposal.</p>

  <h2><a name="Proposed-changes">Proposed Changes</a></h2>
  Change the constructor's declaration in the synopsis in 23.4.2 [pairs.pair]:
  <pre>    <span style="text-decoration: line-through;">template&lt;class U1, class U2&gt; <i>EXPLICIT</i> constexpr pair(U1&& x, U2&& y);</span>
    template&lt;class U1=T1, class U2=T2&gt; <i>EXPLICIT</i> constexpr pair(U1&& x, U2&& y);</pre>

  <p>Likewise, change the declaration around 23.4.2 [pairs.pair] p7:</p>
  <pre>    <span style="text-decoration: line-through;">template&lt;class U1, class U2&gt; _EXPLICIT_ constexpr pair(U1&& x, U2&& y);</span>
    template&lt;class U1=T1, class U2=T2&gt; <i>EXPLICIT</i> constexpr pair(U1&& x, U2&& y);</pre>

  <h2><a name="Acknowledgements">Acknowledgements</a></h2>
  <p>Thanks to Narut Sereewattanawoot for helping discuss this problem and work out this solution.</p>
  <hr />
</body>

</html>