<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>
  <style>
    ins {
      background-color: lightgreen;
    }
  </style>
</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">P1951R1</td>
    </tr>
    <tr>
      <td width="172" align="left" valign="top">Date:</td>
      <td width="435">2021-01-25
      </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="#Feature-test-macro">Feature Test Macro</a><br>
    <a href="#Implementation-experience">Implementation Experience</a><br>
    <a href="#Proposed-changes">Proposed Changes</a><br>
    <a href="#Acknowledgements">Acknowledgements</a>
  </p>

  <h2>Changelog</h2>
  <h3>R1</h3>
  <ul>
    <li>Add section explaining why a feature test macro is unnecessary</li>
    <li>Add section describing implementation experience</li>
    <li>Rebase wording on the latest C++ working draft</li>
  </ul>
  <h3>R0</h3>
  <ul>
    <li>Initial revision</li>
  </ul>

  <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> constexpr explicit(<i>see below</i>) pair(const T1& x, const T2& y);</code></blockquote>

  <p>and</p>

  <blockquote>
    <b>(B)</b><code> template&lt;class U1, class U2&gt; constexpr explicit(<i>see below</i>) 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; constexpr explicit(<i>see below</i>) 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="Feature-test-macro">Feature Test Macro</a></h2>
  <p>It could be argued that this change should also introduce a feature test macro (say,
    <code>__cpp_lib_pair_ctor_default_tmpl_args</code>), but such a macro would be of extremely limited value. Consider
    an example usage such as
  </p>
  <pre>    #ifdef __cpp_lib_pair_ctor_default_tmpl_args
    pair&lt;int, unique_ptr&lt;int&gt;&gt; p{42, {}};
    #else
    pair&lt;int, unique_ptr&lt;int&gt;&gt; p{42, unique_ptr&lt;int&gt;{}};
    #endif</pre>
  <p>This code is needlessly verbose; the second branch of the conditional will work as desired both with and without
    this change. A user who understands the problem addressed by this paper (and thus the need for the feature test
    macro)
    would likely also understand that the
    second branch works in both cases. A user who does not understand the problem addressed by this paper would likely
    not be able to write the code using the feature test macro either.</p>

  <h2><a name="Implementation-experience">Implementation Experience</a></h2>
  <p>This change has been experimentally implemented in a local fork of libc++. The implementation was trivial and all
    existing unit tests passed. Additional unit tests verifying the correct behavior after this proposal also passed.
  </p>

  <h2><a name="Proposed-changes">Proposed Changes</a></h2>
  Change the constructor's declaration in the synopsis in 20.4.2 [pairs.pair]:
  <pre>template&lt;class U1<ins>=T1</ins>, class U2<ins>=T2</ins>&gt; 
  constexpr explicit(<i>see below</i>) pair(U1&& x, U2&& y);</pre>

  <p>Likewise, change the declaration around 20.4.2 [pairs.pair] p11:</p>
  <pre>template&lt;class U1<ins>=T1</ins>, class U2<ins>=T2</ins>&gt; constexpr explicit(<i>see below</i>) 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. Also thanks to Ville
    Voutilainen and Bryce Adelstein Lelbach for their wording guidance.</p>
  <hr />
</body>

</html>